UNIX系サーバーからダウンロードしたテキストファイルを古いメモ帳で開いたら全文が1行に繋がっていた——あるいはチームでソースコードを共有したら、 実質的に何も変えていないのにGitの差分が全行赤く光った。 こういった事象はすべて、OSによって改行コードが違うことが原因です。 この記事では、改行コードという見えない文字がなぜ3種類も存在するのか、どの場面で 何が壊れるのか、そしてどう対処すればいいのかを、歴史的な背景から実務的な対処法まで解説します。
改行コードとは何か
改行コードとは、テキストファイルの中で「ここで行が変わる」ことを表す特殊な制御文字のことです。 普段は目に見えませんが、ファイルの中には確かに存在していて、エディタはそれを検出して行を区切って表示しています。
使われる制御文字は主に2種類で、どちらも古いASCII(American Standard Code for Information Interchange)の制御文字に由来します。
| 略称 | 正式名 | ASCIIコード | エスケープ表記 | 由来 |
|---|---|---|---|---|
| CR | Carriage Return | 0x0D (13) | \r | キャリッジ(印字ヘッド)を行頭に戻す |
| LF | Line Feed | 0x0A (10) | \n | 紙を1行分送る |
タイプライターでは「行頭に戻す(CR)」と「紙を1行送る(LF)」は物理的に別々の動作でした。 初期のコンピュータ(テレタイプ端末など)はこの物理動作をそのまま制御文字として取り込んだため、 改行は2文字(CR + LF)で表すのが自然な発想だったのです。
OSによる改行コードの違い
現代のOSで使われている改行コードは3種類あります。
| OS | 改行コード | バイト列 | 備考 |
|---|---|---|---|
| Windows | CRLF | 0x0D 0x0A | DOS時代から現在まで継続 |
| macOS(現行) | LF | 0x0A | Mac OS X 以降(UNIXベース) |
| Linux / BSD | LF | 0x0A | UNIX系は一貫してLF |
| Classic Mac OS(9以前) | CR | 0x0D | 2001年以前の古いMac。現在はほぼ遭遇しない |
なぜこう分かれたかというと、設計思想の違いです。UNIXは「改行は1文字で表現すれば十分、画面制御は別レイヤーの仕事」 という方針でLFのみを採用しました。DOS/Windowsはプリンタやテレタイプ端末との互換性を優先して、 タイプライター時代の慣習であるCRLFを維持しました。Classic Mac OSはさらに独自の道を進みCRのみを使っていました。Mac OS XでUNIXベースになった結果、macOSは現在LF陣営に移っています。
実務でつまずく場面
1. ExcelでCSVを開くと行が崩れる
UNIXサーバーや業務システムから出力されたLF改行のCSVをExcelで開くと、 改行として認識されず1セルに全部詰め込まれる・途中で行がずれるといった現象が起きます。 Excelは伝統的にCRLFを行区切りとして期待しているためです。
Shift_JIS × CRLFの組み合わせ(日本の業務システムで多い)は比較的素直に開けますが、 UTF-8 × LFのCSVはExcelの「ファイル→開く」ではうまく扱えないことがあります。 対処は改行コード変換ツールで一度CRLFに変換してから開くか、Excelの「データ」タブから「テキスト/CSVから」でインポートして 区切り文字・改行コードを明示的に指定する方法が確実です。
2. Gitの差分が全行になる
チームメンバーがWindowsとmacOS/Linuxで混在していると、同じファイルでも改行コードが異なるだけでGitが全行を「変更」と検出することがあります。内容は変えていないのに、 プルリクエストが全行赤く光ってレビュー不可能になる典型的なパターンです。
対策としてGitにはcore.autocrlfとcore.eolという設定があります。 詳しくは次のセクションで解説します。
3. LFのテキストが古いメモ帳で1行になる
Windows 10 バージョン1809(2018年10月)より前のメモ帳は、LFのみの改行を改行として認識しませんでした。 LinuxやmacOSで作ったテキストをメールで送ったら、受け取った側のWindowsのメモ帳で開くと 全部1行にくっついて表示される、という地味に困る現象がよく起きていました。
現在のWindows 10/11のメモ帳はLF・CR・CRLFすべてに対応していますが、古いソフトや組み込み機器の テキストエディタでは今でもLF非対応のものがあります。互換性を重視する場面ではCRLFで出力しておくのが無難です。
4. シェルスクリプトがWindowsで動かない
Windowsで書いた.shファイルをLinuxで実行すると、bad interpreter: /bin/bash^Mのような謎のエラーが出ることがあります。これはshebang行末尾のCRが邪魔をしているためです。 Linuxのbashは/bin/bash\rというパスを探しに行って見つからず失敗します。 シェルスクリプトやDockerfile、設定ファイルなどUNIX系で実行されるファイルは必ずLFで保存します。
Gitの改行コード設定
Gitには改行コードをコミット時・チェックアウト時に自動変換する仕組みがあります。
| core.autocrlf | コミット時 | チェックアウト時 | 推奨環境 |
|---|---|---|---|
| true | CRLF → LF | LF → CRLF | Windows(やや強め) |
| input | CRLF → LF | 変換しない | macOS / Linux |
| false | 変換しない | 変換しない | すべて手動管理したい場合 |
チームで改行コードを統一する最もトラブルの少ない方法は、リポジトリ直下に.gitattributesファイルを置いてプロジェクトレベルで強制することです。
# .gitattributes の例
* text=auto eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
*.png binary
*.jpg binary
この設定で「原則はLF、Windows専用のバッチ/PowerShellスクリプトだけCRLF、画像ファイルはバイナリ扱い」 という方針が全員に自動的に適用されます。個人のcore.autocrlf設定に関わらず動作するため、チーム開発では必須の設定です。
注意
すでに改行コードが混在したファイルを含むリポジトリで.gitattributesを後から追加すると、次のコミットで大量の差分が発生します。新規リポジトリなら最初から設定する、 既存リポジトリなら「改行コード統一のみ」の独立したコミットとして分離するのが鉄則です。
改行コードの変換方法
実際に改行コードを変換する手段はいくつかあります。状況に応じて使い分けます。
エディタのGUI機能
VSCodeなら画面右下に表示されている「CRLF」または「LF」の表示をクリックすると切り替えられます。 サクラエディタ・秀丸エディタ・TeraPadなども「ファイル→名前を付けて保存」のダイアログで改行コードを指定できます。 日常的な作業ならこの方法が最も手軽です。
コマンドライン
UNIX系のコマンドラインでは以下のようなワンライナーで変換できます。
# CRLF → LF(CR文字を削除)
tr -d '\r' < input.txt > output.txt
# LF → CRLF(各行末にCRを付加)
sed -e 's/$/\r/' input.txt > output.txt
# 専用ツール(インストールが必要)
dos2unix file.txt # CRLF → LF
unix2dos file.txt # LF → CRLF
Node.jsで変換
import { readFileSync, writeFileSync } from 'node:fs'
const text = readFileSync('input.txt', 'utf8')
// CR・CRLF・LF のどれが来てもLFに正規化
const normalized = text.replace(/\r\n|\r/g, '\n')
writeFileSync('output.txt', normalized)
ブラウザで手軽に変換
インストール不要でさっと変換したい場合は、改行コード変換ツールが便利です。テキストを貼り付けるだけでCRLF↔LF↔CRの相互変換ができ、ファイルのアップロードにも対応しています。 CSVの文字化けが改行コードと文字コードのどちらに由来するのか切り分けたいときは文字コード確認ツールやテキスト文字コード変換と併用すると原因究明が早まります。すべてブラウザ内で処理が完結するため、機密情報を含むテキストでも安心です。
CRLFとLF、どちらを使うべきか
結論はプロジェクトの慣習に従うことです。ただし現代の一般的な指針はあります。
- OSS・Web系の開発: LFが事実上の標準。GitHubもデフォルトLF。迷ったらLF
- Windows専用のバッチ/PowerShell/設定ファイル: CRLFで保存しないと動かないケースがある
- 業務システムのCSV出力: 受け手(Excel・取引先システム)が期待する形式に合わせる。日本の業務ではCRLFが多い
- Dockerfile・シェルスクリプト・設定ファイル: 必ずLF。CRが混入すると実行エラーになる
迷う場面の多くは「開発用のコード」と「エンドユーザーに渡すデータ」が混在しているプロジェクトです。 コードはLF、出力データはCRLFというように用途で分けて明示的に管理すれば、 後から原因不明のトラブルに悩まされることは減ります。
まとめ
- 改行コードはASCIIのCR(0x0D)とLF(0x0A)という2つの制御文字の組み合わせで表される
- OS別ではWindows=CRLF・macOS/Linux=LF・Classic Mac OS=CR。タイプライター時代の慣習とUNIXの設計思想の違いに由来する
- 実務ではExcelで行が崩れる・Gitで全行差分・Windowsメモ帳で1行に繋がる・シェルスクリプトの実行エラーとして顔を出す
- チーム開発ではリポジトリに
.gitattributesを置いて改行コードをプロジェクトレベルで統一するのが鉄則 - 変換はエディタのGUI機能・
dos2unix/trコマンド・Node.jsのreplace・ブラウザツールなど複数の手段がある - 現代のOSS開発ではLFが事実上の標準。迷ったらLFを選ぶ