連載
» 2017年04月14日 05時00分 UPDATE

Linux基本コマンドTips(103):【 diff 】コマンド(基本編その2)――テキストファイルの差分をcontext形式などで出力する

本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。前回と今回は、「diff」コマンドです。

[西村めぐみ,@IT]
「Linux基本コマンドTips」のインデックス

連載目次

 本連載では、Linuxの基本的なコマンドについて、基本的な書式からオプション、具体的な実行例までを分かりやすく紹介していきます。今回は、前回に続きテキストファイルを比較して差分を出力する「diff」コマンドです。

diffコマンドとは?

 「diff」は、2つのテキストファイルを比較し、異なる箇所を出力するコマンドです。「diff ファイル1 ファイル2」と実行して、2つのテキストファイル(ファイル1、ファイル2)を比較します。出力内容を“差分”と呼び、patchコマンドで差分を基にファイルを更新したり元に戻したりすることも可能です。似たような機能を備えるコマンドとして本連載第99回で紹介した「comm」コマンドがあります。



diffコマンドの書式

diff [オプション] ファイル1 ファイル2

※[ ]は省略可能な引数を示しています





diffコマンドの主なオプション

 diffコマンドのオプションを3種類に分けて紹介します。最初はコマンドの出力に関する主なオプションです。

短いオプション 長いオプション 意味
-c --context 違いのある箇所をファイルごとに出力し、!記号で変更箇所を示す(context形式、本文参照)
-C 行数 --context=行数 context形式で出力する行数を指定(デフォルトは3行)
-u --unified 違いのある箇所を1つにまとめて、-記号と+記号で変更箇所を示す(unified形式、本文参照)
-U 行数 --unified=行数 unified形式で出力する行数を指定(デフォルトは前後3行)
-行数 異なっている部分の前後の行数を指定(-cまたは-u指定時)
-L ラベル --label=ラベル context形式とunified形式のヘッダに、ファイル名の代わりに出力するラベル(短縮形式「-L」は非推奨、使い方は本文参照)
-p --show-c-function 変更がC言語のどの関数で行われたのかを表示する。「-F'^[_a-zA-Z$]'」相当
-F 正規表現 --show-function-line=正規表現 context形式とunified形式で、各差分のブロックに対し、その前方がパターンにマッチした最後の行の一部を表示
-T --initial-tab normal形式やcontext形式で、テキストの前にスペースでなくタブを出力する(行中でのタブによる桁ぞろえが見やすくなる)
-t --expand-tabs タブによる位置合わせを保存するため、出力のタブをスペースに展開する
--inhibit-hunk-merge 隣接する差分ブロックをマージしない
-D 名前 --ifdef=名前 if-then-else形式で出力する(“名前”はプリプロセッサの条件マクロで使用する名前)
--changed-group-format=フォーマット if-then-else形式で、両方のファイルで異なる行を出力する際のフォーマット
--line-format=フォーマット if-then-else形式で、全ての入力行を出力する際のフォーマット
--new-group-format=フォーマット if-then-else形式で、2番目のファイルだけにある行グループを出力する際のフォーマット
--new-line-format=フォーマット if-then-else形式で、2番目のファイルだけにある行の出力に使用するフォーマット
--old-group-format=フォーマット if-then-else形式で、1番目のファイルだけにある行グループを出力する際のフォーマット
--old-line-format=フォーマット if-then-else形式で、1番目のファイルだけにある行の出力に使用するフォーマット
--unchanged-group-format=フォーマット if-then-else形式で、両方のファイルに共通な行グループを出力する際のフォーマット
--unchanged-line-format=フォーマット if-then-else形式で、両方のファイルに共通な行の出力に使用するフォーマット
-y --side-by-side 2列で出力する(side-by-side)
-W 文字数 --width=文字数 side-by-side形式で出力する幅
--left-column side-by-side形式で、共通な行は左側の列にのみ表示する
--suppress-common-lines side-by-side形式で共通な行を表示しない
-e --ed edコマンドのスクリプト形式で出力する
-n --rcs RCS(バージョン管理システム)形式の差分を出力する
-l --paginate prコマンドによるページ付けを行う
--strip-trailing-cr 行末のCRを取り除く
-q --brief ファイルが違うかどうかだけを出力する
-s --report-identical-files 2つのファイルが同じだったときも出力する

 diffコマンドの比較方法に関する主なオプションは次の通りです。

短いオプション 長いオプション 意味
-i --ignore-case 大文字と小文字の違いを無視する
-B --ignore-blank-lines 空行の有無を無視する
-b --ignore-space-change スペースの数だけが異なる場合は違いを無視する
-E --ignore-tab-expansion タブ展開によるスペースの変更を無視する
-w --ignore-all-space 空白を無視して比較する
-I 正規表現 --ignore-matching-lines=正規表現 パターンにマッチするような行を挿入・削除するだけの変更を無視する
-H --speed-large-files 小さな変更が大量にあるような大きなファイルを高速に扱うためにヒューリスティックな手法を用いる(短縮形式「-H」は非推奨)
-d --minimal より小さな差分を生成する(動作が遅くなる)
--horizon-lines=行数 差分の前後にある共通部分を保持する行数
-a --text ファイルを強制的にテキストと見なして1行ずつ比較する

 diffコマンドのディレクトリ比較に関する主なオプションは次の通りです。

短いオプション 長いオプション 意味
-r --recursive ディレクトリを比較するとき、サブディレクトリも再帰的に比較する
-S ファイル名 --starting-file=ファイル名 ディレクトリを比較する際の開始ファイル(中断した比較を続行する際に利用)
--ignore-file-name-case ファイルを比較する際に、ファイル名の大文字小文字を無視する
--no-ignore-file-name-case ファイルを比較する際に、ファイル名の大文字小文字を考慮する
-N --new-file ディレクトリを比較する際、片方のディレクトリにのみファイルが存在していた場合、“新規ファイルとの比較”として動作する
-P --unidirectional-new-file 2番目のディレクトリにのみファイルが存在していた場合のみ、新規ファイルとの比較として動作する(短縮形式「-P」は非推奨)
-x パターン --exclude=パターン ディレクトリを比較する際に、除外するファイルを指定する
-X リスト --exclude-from=リスト ディレクトリを比較する際に無視する名前のパターンが書かれたファイルを読み込む


変更箇所の前後も合わせて出力する“context形式”と“unified形式”

 「diff ファイル1 ファイル2」で、ファイル1とファイル2のうち異なる箇所だけが出力されます(連載102回)。差分ファイルを配布する際には、前後の行を含めた状態で出力することが一般的です。

 例えば、オリジナルのファイルに対し、AさんとBさんがそれぞれ別々に修正を施した場合、行番号がずれている可能性があります。差分ファイルに前後の行が出力されていると、行番号がずれていても修正を反映しやすくなります。

 このような目的で前後の行を出力する場合、“context形式”または“unified形式”を使用します。

 context形式は1つ目のファイルの内容と2つ目のファイルの内容を別々に出力します。これに対し、unified形式は1つ目のファイルの内容と2つ目の内容を合わせた状態で出力します。

差分をcontext形式で出力する

 context形式を指定するには、画面1のように「-c」オプションまたは「--context」オプションを使います。

 出力の冒頭には「*** 1つ目のファイル名」と「--- 2つ目のファイル名」という2行が示されます。続いて「*** 1つ目のファイルの開始行番号と終了行番号 ***」、その後、該当箇所と前後の行の内容が表示されます。

 2つ目のファイルと内容が異なっている行は行頭に「!」記号が、2つ目のファイルに存在しない行では行頭に「-」が出力されています。

 後半は「--- 2つ目のファイルの開始行番号と終了行番号 ---」に続いて、該当箇所と前後の行の内容が出力されます。

 1つ目のファイルと異なっている行は行頭に「!」記号が、1つ目のファイルには存在しない行、つまり2つ目のファイルで追加された行には行頭に「+」記号が付いています。

 異なっていた箇所の前後3行が合わせて出力されるため、例えば4行目と8行目が異なっている場合は1〜12行目がまとめて表示されます。前後の行数を3行から変更したい場合は「-C 行数」または「--context=行数」オプションで指定します。

 画面2では、結果の違いを見やすくするために、前後1行を表示するよう指定しています。なお、patchコマンドで差分を反映させたい場合は3行以上の指定が推奨されています。

 以下の実行例で使用したファイル(list1.csvとlist2.csv)の内容は、第102回と同じです。

コマンド実行例

diff -c ファイル1 ファイル2

(ファイル1とファイル2の差分をcontext形式で出力する)(画面1

diff -C 行数 ファイル1 ファイル2

(変更箇所の前後に出力する行の数を指定する)

diff -C 1 ファイル1 ファイル2

(context形式で前後1行だけ出力する)(画面2


画面1 画面1 ファイル1とファイル2の差分をcontext形式で出力
画面2 画面2 context形式で前後1行だけ出力


差分をunified形式で出力する

 unified形式を指定するには、画面3のように「-u」オプションまたは「--unified」オプションを使います。「-c」オプション同様、デフォルトでは前後3行を含めて表示されます。「-U 行数」または「--unified=行数」オプションで表示する行数を変更できます。

 まず、「--- 1つ目のファイル名」と「+++ 2つ目のファイル名」が表示されます。続いて「@@ -1つ目のファイルの開始行と表示行数 +2つ目のファイルの開始行と表示行数 @@」が表示され、該当箇所の内容が出力されます。

 このとき、異なっている箇所には「-」記号または「+」記号が出力されます。「-」は1つ目のファイルの内容、「+」は2つ目のファイルの内容という意味です。

 画面4では、結果の違いを見やすくするために、前後1行と指定しています。なお、patchコマンドで差分を反映させたい場合は3行以上の指定が推奨されています。

コマンド実行例

diff -u ファイル1 ファイル2

(ファイル1とファイル2の差分をunified形式で出力する)(画面3

diff -U 行数 ファイル1 ファイル2

(変更箇所の前後に出力する行の数を指定する)

diff -U 1 ファイル1 ファイル2

(unified形式で前後は1行だけ出力)(画面4


画面3 画面3 ファイル1とファイル2の差分をunified形式で出力
画面4 画面4 unified形式で前後は1行だけ出力


ラベルを変更する

 context形式とunified形式のどちらも、出力の先頭にはファイル名とタイムスタンプが出力されています。この部分の内容を変更したい場合は「--label=ラベル」を指定します。

 例えば、「--label ファイル1の名前 --label ファイル2の名前」と指定すると、ファイル名のみとなります(画面5)。

コマンド実行例

diff -u --label ラベル1 --label ラベル2 ファイル1 ファイル2

(出力の冒頭の表示内容を変更)


画面5 画面5 出力の冒頭の表示内容を変更


筆者紹介

西村 めぐみ(にしむら めぐみ)

PC-9801NからのDOSユーザー(LinuxはPC-486DXから)。1992年より生産管理のパッケージソフトウェアの開発およびサポート業務を担当。のち退社し、ライターとして活動。著書に『図解でわかるLinux』『らぶらぶLinuxシリーズ』『はじめてでもわかるSQLとデータ設計』『シェルの基本テクニック』など。2011年より、地方自治体の在宅就業支援事業にてPC基礎およびMicrosoft Office関連の教材作成およびeラーニング指導を担当。


Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。