DIFF(1) | General Commands Manual | DIFF(1) |
diff - 2 つのファイル間の違いを探す
diff [-abcdefhilnpqrstuwyBEHNPT] [-LINES] [-x PATTERN] [-C LINES] [-D NAME] [-F REGEXP] [-I REGEXP] [-L LABEL] [-S FILE] [-U LINES] [-W COLUMNS] [-X FILE] [--binary] [--brief] [--changed-group-format=fORMAT] [--context[=LINES]] [--diff-program=PROGRAM] [--ed] [--exclude=PATTERN] [--exclude-from=FILE] [--expand-tabs] [--forward-ed] [--from-file=FILE] [--horizon-lines=LINES] [--ifdef=NAME] [--ignore-all-space] [--ignore-blank-lines] [--ignore-case] [--ignore-file-name-case] [--ignore-matching-lines=REGEXP] [--ignore-space-change] [--ignore-tab-expansion] [--inhibit-hunk-merge] [--initial-tab] [--label=LABEL] [--left-column] [--line-format=FORMAT] [--minimal] [--new-file] [--new-group-format=FORMAT] [--new-line-format=FORMAT] [--no-ignore-file-name-case] [--old-group-format=FORMAT] [--old-line-format=FORMAT] [--paginate] [--rcs] [--recursive] [--report-identical-files] [--sdiff-merge-assist] [--show-c-function] [--show-function-line=REGEXP] [--side-by-side] [--speed-large-files] [--starting-file=FILE] [--strip-trailing-cr] [--supress-common-lines] [--text] [--to-file=FILE] [--unchanged-group-format=FORMAT] [--unchanged-line-format=FORMAT] [--unidirectional-new-file] [--unified[=LINES]] [--width=COLUMNS] FROMFILE TOFILE
diff [-v] [--help] [--version]
diff は 2 つのファイルを比較し、それらの違いを記述して出力する。
もっとも簡単な場合は、比較対象のファイルは FROMFILE と TOFILE である。これらのファイルのうちのどちらかは `-' と指定しても良い。この時はそのファイルは標準入力から読み込まれる。
FROMFILE がディレクトリで TOFILE がディレクトリではない場合、 diff はディレクトリ FROMFILE にある、ファイル名が TOFILE のファイルを比較対象にする (逆も同様)。 ディレクトリでない方の指定を `-' にすることはできない。
両方がディレクトリのときは、 diff は双方のディレクトリにある、対応するファイルを アルファベット順にそれぞれ比較する。 比較は再帰的には行われないが、 -r または --recursive オプションを指定すれば再帰的になる。 diff はディレクトリの内容そのものをファイルのように比較することはしない。 フルパス指定のファイルは `-' であってはならない。なぜなら標準入力には名前がないので、 「同名のファイル」という概念が使えないからである。
--from-file=FILE オプションが与えられると、任意の数のファイル名を与えることができ、 それぞれのファイルは FILE と比較される。 同様に、 --to-file=FILE オプションが与えられると、それぞれ指定されたファイルは FILE と比較される。 [訳注: 2.7 にはこれらのオプションは存在しない]
context 出力形式は 2 行のヘッダからはじまる。 これは以下のようなものである:
*** FROMFILE FROMFILE-MODIFICATION-TIME --- TOFILE TOFILE-MODIFICATION-TIME
-L LABEL を用いるとヘッダの内容は変化する。 次に来るのは hunk (テキストブロック) である。 繰り返し登場することもある。 context 形式の hunk は以下のようなものである:
*************** *** FROMFILE-LINE-RANGE ****
FROMFILE-LINE
FROMFILE-LINE... --- TOFILE-LINE-RANGE ----
TOFILE-LINE
TOFILE-LINE...
異なっている行の周辺のコンテクストの各行には、 先頭に 2 つのスペースがついている。 2 つのファイル間で異なっている行には、 先頭に表示文字とスペースがつく。
hunk の全ての変更が挿入であれば、 FROMFILE 各行は省略される。また全ての変更が削除であれば、 TOFILE 各行は省略される。
--- FROMFILE FROMFILE-MODIFICATION-TIME +++ TOFILE TOFILE-MODIFICATION-TIME
-L LABEL を用いるとヘッダの内容は変化する。 次に来るのは hunk (テキストブロック) である。繰り返し登場することもある。 それぞれの hunk はファイルの異なっている 1 つ 1 つの部分を示している。 unified 形式の hunk は以下のようなものである:
@@ FROMFILE-RANGE TOFILE-RANGE @@ LINE-FROM-EITHER-FILE LINE-FROM-EITHER-FILE...
両者で共通な行の前には 1 つのスペースが置かれる。 異なる行の前には以下の表示文字が置かれる:
ファイルは 2 列に表示され、間にのど (gutter) が置かれる。 のどには以下のマーカーのいずれか 1 つが含まれる。
side-by-side 形式が一番読みやすいような場合もあるが、限界もある。 この形式は通常よりもずっと広い幅の出力を生成し、 長すぎる行は折り畳んでしまう。 またこの出力では通常よりも文字の整列への依存が大きくなるので、 等幅フォントを使っていなかったり、通常と異なるタブストップを使っていたり、 印字されない文字を使っていたりすると、出力が非常に醜くなる。
1 つ以上の差分 hunk から構成される。 末尾に近い方の変更が先に現れ、行数の変化が以降の ed の行番号解釈に影響しないようになっている。 ed 形式の hunk は以下のようなものである:
CHANGE-COMMAND TO-FILE-LINE TO-FILE-LINE... .
ed は入力の末尾を表すためにピリオド 1 つだけの行を用いるので、 diff は変更された行のうち、ピリオド 1 つだけの行を ピリオド 2 つに変更してプロテクトし、 続けて 2 つのピリオドを 1 つにする ed コマンドを書く。 ed 形式は改行されていない行を表すことができない。 したがって 2 番目のファイルの最終行が変更されていて、 かつ改行されていなかった場合、 diff はエラーを報告して、改行があるかのように動作する。
変更コマンドには 3 つの種類がある。 それぞれ、1 番目のファイルの行番号 (またはコンマ区切り指定の行範囲指定)、 続けて変更の種類を示す 1 文字の文字からなる。 行番号は、すべてファイルのオリジナルの行番号である。 変更コマンドの種類は以下の通り:
diff は ed スクリプトのような出力で、かつ各 hunk が forward 方向 (先頭から末尾へ) のような出力も生成できる。コマンドの形式もちょっと変化している。 コマンド文字が、修正する行や行範囲の先に来るのである。 また、ピリオド 1 つだけの行を特別扱いすることもしない。 ed 形式と同様に、forward ed 形式も改行していない行を表すことはできない。
forward ed 形式はあまり便利ではない。なぜなら ed も patch もこの形式の diff を用いることができないからである。 これは主に古いバージョンの diff との互換性のために存在している。
RCS 出力形式は Revision Control System (RCS) で用いるために特別に設計されたものである。 RCS はバージョンやシステムの異なるファイルを扱うための、 フリーなプログラムセットである。 この形式は forward ed 形式と似ているが、 ピリオド 1 つの行や改行していない行の問題を回避しているので、 ファイル内容の任意の変更を表すことができる。 テキストセクションをピリオド 1 つの行で終わるのではなく、 それぞれのコマンドで、適用する行数を指定しているのである。また `c' コマンドの代わりに `a' と `d' の組み合わせを用いている。 さらに 2 番目のファイルの末尾が変更されていて、 かつ改行で終わっていない場合には、 出力の末尾も改行されない状態で終わる。
diff を用いて 2 ファイルの C ソースコードをマージすることもできる。 この出力形式には、両方のファイルの行がすべて含まれる。 両方のファイルに共通な行は一度しか登場しない。 異なる部分は C プリプロセッサの指定を用いて分離される。 #ifdef NAME または #ifndef NAME, ,BR #else ", and " #endif である。 出力をコンパイルするとき、マクロ NAME を定義したり、未定義のままにすることによって、 どちらのバージョンを使うかを選択できる。
例えば、`wait (&s)' というインスタンスを `waitpid (-1, &s, 0)' に変更し、新旧のファイルを `--ifdef=HAVE_WAITPID' オプションによってマージすると、 影響を受けた部分のコードは以下のようになるだろう:
do {
#ifndef HAVE_WAITPID
if ((w = wait (&s)) < 0 && errno != EINTR)
#else /* HAVE_WAITPID */
if ((w = waitpid (-1, &s, 0)) < 0 && errno != EINTR)
#endif /* HAVE_WAITPID */
return w;
} while (w != child);
行グループ形式を用いると、 if-then-else 入力を受け入れる多くのアプリケーションに適した形式を指定できる。 例えばプログラミング言語や文書整形言語などが挙げられる。 行グループ形式は、 似ている行からなる隣接したグループの出力形式を指定する。
例えば、以下のコマンドは TeX ファイル `old' と `new' を比較し、 old の部分を `\begin{em}'-`\end{em}' で囲み、 new の部分を `\begin{bf}'-`\end{bf}' で囲んでマージしたかたちで出力する。
diff \
--old-group-format='\begin{em}
%<\end{em}
' \
--new-group-format='\begin{bf}
%>\end{bf}
' \
old new
以下のコマンドも上記の例と同じだが、やや記述が多い。 デフォルトの行グループ形式も指定しているからである。
diff \
--old-group-format='\begin{em}
%<\end{em}
' \
--new-group-format='\begin{bf}
%>\end{bf}
' \
--unchanged-group-format='%=' \
--changed-group-format='\begin{em}
%<\end{em}
\begin{bf}
%>\end{bf}
' \
old new
次にもう少し進んだ例を紹介する。これは差分リストを、
"plain English"
スタイルで行番号を書いたヘッダとともに出力する。
diff \
--unchanged-group-format='' \
--old-group-format='-------- %dn line%(n=1?:s) deleted at %df:
%<' \
--new-group-format='-------- %dN line%(N=1?:s) added after %de:
%>' \
--changed-group-format='-------- %dn line%(n=1?:s) changed at %df:
%<-------- to:
%>' \
old new
行グループ形式を指定するには、 diff を以下のオプションのどれか 1 つを指定して実行する。 4 つまでの行グループ形式を指定でき、 各指定がそれぞれ行グループ 1 つに対応する。 FORMAT にはシェルのメタキャラクタが入っていることが多いので、 クォートするべきであろう。
例えば `%(N=0?no:%dN) line%(N=1?:s)' は N (new ファイルからのグループの行数) が 0 なら `no lines' となり、 N が 1 なら `1 line' となり、それ以外の場合は `%dN lines' となる。
printf 変換指定には %d, %o, %x, %X (それぞれ 10 進, 8 進, 小文字 16 進, 大文字 16 進) が使える。 `%' の後には以下のオプションを順に指定できる。 `-' (左詰めの指定)、整数 (フィールドの最低幅)、 ピリオドと数値 (数値は省略可; 桁数の最小値) である。 例えば `%5dN' は new ファイルからのグループの行数を、 5 文字幅のフィールドに、 printf の "%5d" 書式を用いて表示する。
行形式は、入力から取得された各行を if-then-else 形式の 行グループとして出力される際の制御を行う。
例えば、以下のコマンドは、テキストの左に変更表示の 1 文字を表示して テキストを出力する。出力の最初の桁は、削除行では `-'、 追加行では `|' となり、変更されなかった行ではスペースとなる。 この形式では、改行が必要な部分には改行を入れて出力する。
diff \
--old-line-format='-%l
' \
--new-line-format='|%l
' \
--unchanged-line-format=' %l
' \
old new
行形式を指定するには、以下のオプションのどれかを用いる。 FORMAT にはシェルのメタキャラクタが入っていることが多いので、 クォートするべきであろう。
行形式では、普通の文字はそれ自身を表す。変換指定は `%' で始まり、以下の形式をとる:
デフォルトの行形式は `%l' に改行文字を続けたものである。入力にタブ文字があり、 それが出力行の桁揃えに重要である場合には、`%l' や `%L' の行指定を タブストップの直後に置くとよい (すなわち `%l' や `%L' の前にタブ文字を置けばよい)。 あるいは -t オプションを用いるのもよいだろう。
行形式と行グループ形式を同時に用いると、様々な形式指定が可能となる。 例えば、以下のコマンドは diff の通常の形式と似た形式の指定である。 これを修正すれば、diff の出力を微調整することが可能になる。
diff \
--old-line-format='< %l
' \
--new-line-format='> %l
' \
--old-group-format='%df%(f=l?:,%dl)d%dE
%<' \
--new-group-format='%dea%dF%(F=L?:,%dL)
%>' \
--changed-group-format='%df%(f=l?:,%dl)c%dF%(F=L?:,%dL)
%<---
%>' \
--unchanged-group-format='' \
old new
diff への 2 つの引数がディレクトリだった場合、 両方のディレクトリにそれぞれのファイルが、 ファイル名のアルファベット順に比較される。 通常はファイルのペアに違いが全くなければ、何も出力しない。 しかし -s オプションを用いると、同一のファイルも報告する。 両方のディレクトリに同名のサブディレクトリがあると、 通常 diff は報告だけしてサブディレクトリ以下のファイルは比較しない。 しかし -r オプションを用いると、 ディレクトリツリーを辿れる限り、対応する全てのファイルを比較する。
片方のディレクトリだけにあるファイルに対しては、 diff は通常存在するファイルの内容を表示せず、 ファイルが片方にあって他方にはないことだけを報告する。 diff の振舞いを変えて、 他方のディレクトリにもファイルが空の状態で存在するかのように 動作させることもできる。すなわち diff は実際に存在するファイルの内容をすべて出力する。 (この出力は、ファイルが第 1 ディレクトリにあれば削除、 第 2 ディレクトリにあれば挿入となる。) この指定には -N オプションを使う。
古いほうのディレクトリに大きなファイルがあって、 新しいほうにはない場合、 -N オプションの代わりに -P オプションを用いるとパッチの大きさを小さくできる。 -P オプションは -N オプションと似ているが、第 2 ディレクトリにあるファイルの内容だけを 出力に挿入し、第 1 ディレクトリだけにあるファイルは無視する (すなわち、追加されたファイルだけを扱う)。 そして、パッチを当てる前に消去されたファイルを削除するよう、 パッチの先頭にパッチを当てるユーザーへの指示を書く。
ディレクトリの比較時に特定のファイルを無視させるには、 -x PATTERN オプションを用いる。シェルとは異なり、ファイル名の先頭のピリオドは、 パターン先頭のワイルドカードにマッチする。 シェルによって展開されないよう、 PATTERN はクォート記号で囲うべきである。 例えば `-x '*.[ao]'' は `.a' や `.o' で終わる名前のファイルをすべて無視する。 このオプションは、複数指定するとそれぞれが有効になる。 例えば `-x 'RCS' -x '*,v'' というオプションを指定すると、 ファイル名が `RCS' だったり `*,v' で終わるような ファイルとサブディレクトリをすべて無視する。
diff は以下の値のどれかで終了する:
プログラムのバグについては bug-gnu-utils@gnu.org へ報告してください。 ページの更新は Ragnar Hojland Espinosa <ragnar@ragnar-hojland.com> が行っています。
October 2002 | GNU diff Utilities 2.8.1 |