diff - ファイルの差分を確認する

diff

diffコマンドは、ファイルの差分を確認するコマンドになります。異なるバージョンのファイルを比較するのに利用できます。ディレクトリ同士の比較を行う場合は、同じファイル名同士を比較して、比較結果を表示することができます。また、差分の出力をファイルに保存し、patchコマンドでファイルに対して差分を書き込むことで差分を出したファイルに変更できます。

スポンサーリンク

diffコマンドの利用例

2つのファイルの差分を表示
(オプションなし)

diffは、2つのファイルを引数にすることで、指定した2つのファイルの差分を表示することが出来ます。例えば、複数のバージョンがあるファイルについて、2つのファイルがどのように異なっているかを確認出来ます。

コマンド例

point-v1.txt

number,name,point
1,aaa,100
2,ccc,80
3,eee,90

point-v2.txt

no.,name,point
1,aaa,100
2,bbb,28
3,ccc,80
4,ddd,65
5,eee,90

実行結果

diffの実行結果の出力形式はnormal形式の出力です。差分の表示の見方は、たとえば、

で一つのまとまりになります。

normal形式の最初の一行目は、引数の左のファイルの行番号、変更内容を示すシンボル(a(add):追加・d(delete):削除・c(change):変更)、引数の右のファイルの行番号を表します。また、行番号がカンマで区切られているとその行の範囲を表しています。
その次の行からは'<'で始まる行は左のファイルにある行で、'>'で始まる行は右のファイルにある行になります。シンボルがcの場合は、'---'で変更のある行が区切られます。

他の実行結果として、行の追加や行の削除の結果は以下のようになります。

point-v1-add.txt

number,name,point
1,aaa,100
2,ccc,80
3,eee,90
4,fff,34

point-v1-delete.txt

number,name,point
1,aaa,100
3,eee,90

コマンド例と実行結果

2つのファイルを並べて表示
(-yオプション)

-yオプション(--side-by-sideオプション)はファイルの比較結果を並べて表示できます。diffコマンドで2つのファイルの内容を表示して確認したい場合に利用できます。

コマンド例

実行結果

diff_y_option1

出力行の幅を調整したい場合は、-Wオプションが利用できます。

コマンド例

実行結果

diff_y_option2

また、共通行を表示したくない場合は、--suppress-common-linesオプションが利用できます。

コマンド例

実行結果

diff_y_option3

context形式の出力を表示
(-cオプション)

diffコマンドの出力形式にはいくつか別の形式があります。-cオプションを用いるとcontext形式の出力でファイルの差分を表示することができます。

コマンド例と実行結果

context形式の最初の2行は、ファイルを示す記号・ファイル名・修正時間(mtime)を表します。

そのあとの行に、変更がある行番号と差分を示す行を表示します。

変更に関する記号は3つあり、

変更を表す記号が'!'
追加を表す記号が'+'
削除を表す記号が'-'

になります。

追加と削除の記号についての実行結果は以下のようになります。

実行結果とコマンド例

unified形式の出力の表示
(-uオプション)

-uオプションはunified形式の差分の出力を表示します。unified形式はGitでの差分でよく見る形式になります。

コマンド例と実行結果

unified形式の最初の2行は、ファイルを示す記号・ファイル名・修正時間(mtime)を表します。

その次にそれぞれのファイルの変更のある行の範囲が表示されます。

更にその次の行にそれぞれのファイルの行が表示されます。

行の最初にある文字が、'-'ならば引数の左のファイルの行、'+'ならば引数の右のファイルの行、何もない場合は共通行を表します。

ディレクトリ内のファイル比較
(オプションなし)

diffコマンドでディレクトリを指定するとディレクトリ内のファイルで、同じ名前のファイルの差分を表示します。

また、オプションがない場合は、ディレクトリ内のサブディレクトリの中までは、比較を行いません。サブディレクトリも比較したい場合は-rオプションを使用します。

v1のディレクトリ

v2のディレクトリ

コマンド例と実行結果

シンボリックリンクをたどりたくない場合は、--no-dereferenceオプションを使用します。この場合は、シンボリックリンク先が同じ名前のファイルの場合に等しい判定になります。

再帰的なディレクトリの比較
(-rオプション)

-rオプションを用いると、ディレクトリを比較したときにディレクトリの内のサブディレクトリも含めて、ファイルを比較し、差分を表示できます。

コマンド例と実行結果

ファイルが異なるがどうかの判定
(-qオプション)

-qオプション(--briefオプション)は、単純にファイルが同じ内容か違う内容かということを表示します。

コマンド例と実行結果

ディレクトリ同士を比較したときの方が、よりこのオプションの効果が分かりやすいです。

コマンド例と実行結果

差分箇所のC言語での関数名を表示
(-pオプション)

-pオプションを用いると、context形式の出力で差分個所のC言語での関数名を表示できます。関数名の表示については、Cのソースコードに対してインデントされていることが前提になります。また、差分個所の近くに関数名が存在する場合は表示を行いません。

hello.c

hello2.c

コマンド例と実行結果

-pオプションの結果として、ファイル名と差分の仕切りになっている文字列の後に

のように関数名が表示されます。この-pオプションはunified形式でも使用できます。

コマンド例と実行結果

unified形式の場合は

のように行の範囲の後に関数名が表示されます。

差分個所の関数名表示の正規表現を指定
(-Fオプション)

-Fオプションは-pオプションで表示した関数名の表示部分をgrepコマンドの正規表現と同じように指定することができます。指定した正規表現で表示される文字列はcontext形式またはunified形式で利用できます。
また、-pオプションは形式が指定されていない場合は、-c -F '^[[:alpha:]$_]'と同じ意味になります。

つまり、セクションが分かれるようなテキストファイルは、-Fオプションを用いることで差分の箇所のヒントを表示できます。

例えば、rubyでのソースコードで関数名についてのヒントを表示したい場合は、表示したい場所(ここでは、defの宣言がある場所)を指定するように正規表現を指定します。

hello.rb

hello2.rb

コマンド例と実行結果(context形式)

コマンド例と実行結果(unified形式)

ここでの

-F'^[[:space:]]*def'

の意味として、^が行の始めを示し、[[:space:]]の文字クラスはスペースやタブを表します。

正規表現として表すところは、行の始めから0回以上のスペースやタブ文字の後に'def'という文字がある行になります。つまり、インデントがされているかもしれないdefの宣言箇所の行をヒントとして表示する意図があります。

-Fオプションで指定する正規表現は、-Fオプションを複数回使用することで増やすことができます。

ファイルをパッチ

diffコマンドの内容を保存することでパッチファイルを作成できます。diffコマンドの基本的な構文は

diff [option]... <from-file> <to-file>

のように表すことができます。diffコマンドの出力をファイルに保存すると、from-fileからto-fileへのパッチファイルを作成できます。

このパッチファイルはpatchコマンドを用いると元のファイル(from-file)から差分を取ったファイル(to-file)を作成できます。patchコマンドは

patch [option]... <from-file> <patchfile>

のように使用できます。

コマンド例と実行結果

diffコマンドとpatchコマンドを組み合わせることで、簡単にバージョン間の差異を修正することができます。diffコマンドとpatchコマンドはとても便利なので、セットで覚えておいて損はないコマンドになります。

参考

GNU diffutils - Comparing and Merging Files