Linux / コマンド / diff - テキストファイルとディレクトリの違いを比較

diffは、2つのテキストファイルまたはディレクトリを比較して、異なる部分を表示するコマンドです。特に-uのunified diff形式は、変更前後の文脈を一緒に提供するため、パッチやコードレビューで広く使用されます。

この記事ではdiffの基本的な文法と主なオプション、実際の使用例、関連コマンドとの違い、使用時の注意点について説明します。

diffコマンドとは?

1つ目から2つ目へどの行が変わったかを差分として計算します。終了状態は、指定した比較条件で差分がなければ0、差分があれば1、GNU版の比較エラーは通常2です。標準出力が空でもエラーがないとは限らないため、診断と終了状態も確認してください。空白を無視するオプションを使った場合の「差分なし」は、バイト単位で同一という意味ではありません。

基本的な文法

diff [オプション] ファイル1 ファイル2
diff [オプション] ディレクトリ1 ディレクトリ2

オプションや詳細な動作は実装やバージョンによって異なる場合があります。現在のシステムではdiff --helpとman diffでインストールされたコマンドの説明を確認してください。

diffの基本的な使い方

2つのファイルを比較する

基本的な出力は変更コマンドの形式で表示されます。

diff old.conf new.conf

unified形式で比較する

変更行の前後の文脈が一緒に表示され、人が読みやすくなります。

diff -u old.conf new.conf

ディレクトリを再帰的に比較する

対応するサブパスまで再帰的に比較します。ファイルの内容や存在の差を調べるもので、所有権や権限の一致まで保証しません。属性はstatによるファイル情報の確認も併用します。GNU版では通常リンク先を比較するため、リンク自体を比較したい場合は対応する --no-dereference を確認してください。

diff -ru project-old project-new

変更表示と終了ステータスの読み取り

diff -uは二つのファイルの異なる行をunified形式で表示します。以下の例では、最初のファイルのoldが二番目のファイルのnewに変更されました。

printf 'old\n' > before.txt
printf 'new\n' > after.txt
diff -u before.txt after.txt

出力の主要部分(ファイルヘッダーの時刻は省略):

-old
+new

-は最初のファイルにのみある行、+は二番目のファイルにのみある行です。二つのファイルが異なる場合、終了ステータスは1であり、これを実行失敗ステータス2と区別してください。

主なオプション

オプション 説明
-u unified形式で文脈と差分を出力します。
-r, --recursive サブディレクトリを再帰的に比較します。
-q, --brief 詳細な差異の代わりに異なるかどうかだけを報告します。
-s, --report-identical-files 同一のファイルも明示的に報告します。
-w, --ignore-all-space 行内の空白の有無や量を無視します。行の区切りそのものを無視する指定ではありません。
-b, --ignore-space-change 行末の空白と、その他の1文字以上の空白の連続の量の違いを無視します。空白なしと空白ありは区別します。
-i, --ignore-case 大文字と小文字の差異を無視します。
--color=auto サポートされているGNUバージョンで端末出力に色を付けます。

実践的活用例

パッチファイルを作成する

実在する original.conf と modified.conf を用意し、差分を未使用の出力名へ保存します。差分があれば終了状態1でもパッチは保存されますが、状態2などのエラー時には完全な出力と判断しないでください。適用する側の作業場所で解釈できる相対パスを使い、まず保存内容を確認します。

diff -u original.conf modified.conf > config.patch

ディレクトリの変更を要約する

ファイルの内容全体が必要ない場合は、-qrで内容が異なるファイルと片方にしかないパスを要約します。

diff -qr release-a release-b

空白の違いを除いて確認する

空白に意味がない場合にのみ使用します。Pythonのようにインデントが意味を持つ言語では、結果を慎重に解釈します。

diff -u -b before.txt after.txt

diffと関連するコマンドの比較

コマンド 主な役割 適した状況
diff 行単位のテキストの違い 設定・ソース・ディレクトリの比較
cmp バイト単位での最初の違い 同一かどうかとオフセットの確認
git diff リポジトリ変更の比較 Git作業ツリーとコミット
comm ソートされた二つのファイルの集合の比較 共通・固有行の分離

使用する際の注意点

終了ステータス1は差異があることを意味します

スクリプト内で単純なエラーとして処理すると、正常な比較結果を失敗と誤解することがあります。

バイナリファイルには詳細な行比較は適していません

バイト単位の同一性はcmpコマンドによる比較やチェックサムで確認できます。通常の diff はバイナリの詳細な行比較には向きません。

空白の無視は実際の違いを隠すことがある

形式やインデントが意味を持つファイルには、無視オプションを安易に適用しません。

FAQ

diff の出力がない場合は何を意味しますか?

比較が正常終了し、終了状態が0であれば、選んだ比較条件で報告すべき差分がないことを示します。空白無視などの指定やエラー診断も確認してください。

最も読みやすい出力形式は何ですか?

一般的には、diff -u の unified 形式が文脈と共に表示され、読みやすいです。

ディレクトリ全体も比較できますか?

-rでサブディレクトリを再帰的に比較できます。

diffが終了コード1を返した場合、それはエラーですか?

いいえ。通常は差異が見つかったことを示す正常な結果で、GNU版の比較エラーは通常2です。シグナルなどによる異常終了は別途確認します。

参考資料