このページでは、ファイルの差分を表示するコマンド「diff」と、diffで作成できる差分パッチファイルを用いてパッチを当てる方法を紹介します。
Last login: Sun Jan 5 02:14:00 on ttyp2 Welcome to Darwin! [Macintosh:~] hiro% cd terminaltest [Macintosh:~/terminaltest] hiro% ls 1 2 test1.txt test2.txt test3.txt test4.txt test5.txt [Macintosh:~/terminaltest] hiro% ls 1 01.txt 02.txt 1 [Macintosh:~/terminaltest] hiro% ls 2 01.txt 02.txt 1 [Macintosh:~/terminaltest] hiro% ls 1/1 01.txt 02.txt [Macintosh:~/terminaltest] hiro% ls 2/1 01.txt 02.txt
今回の実験には上記のファイルを使用します。~/terminaltestに、各々内容の異なるtest1.txt、test2.txt、test3.txt、test4.txt、test5.txtというテキストファイルと、1、2というディレクトリがあり、ディレクトリ1、2はどちらとも01.txt、02.txtというテキストファイルと、サブディレクトリ1を含み、各サブディレクトリ1にも01.txt、02.txtというテキストファイルが含まれています(ややこしくてゴメンナサイ)。
では、試してみましょう。
[Macintosh:~/terminaltest] hiro% cat test1.txt abc def ghi [Macintosh:~/terminaltest] hiro% cat test2.txt abc jklm Ghi
このような内容のtest1.txt、test2.txtについて、diffを使ってみましょう。基本的な使い方は「diff 比較するファイル1 比較するファイル2」です。
[Macintosh:~/terminaltest] hiro% diff test1.txt test2.txt 2,3c2,3 < def < ghi --- > jklm > Ghi
このように、違っている部分が表示されますが、ちょっと分かりにくいですね。もう少し分かりやすく表示してみましょう。
[Macintosh:~/terminaltest] hiro% diff -c test1.txt test2.txt *** test1.txt Sun Jan 5 02:02:44 2003 --- test2.txt Sun Jan 5 02:03:02 2003 *************** *** 1,3 **** abc ! def ! ghi --- 1,3 ---- abc ! jklm ! Ghi [Macintosh:~/terminaltest] hiro% diff -u test1.txt test2.txt --- test1.txt Sun Jan 5 02:02:44 2003 +++ test2.txt Sun Jan 5 02:03:02 2003 @@ -1,3 +1,3 @@ abc -def -ghi +jklm +Ghi [Macintosh:~/terminaltest] hiro% diff -y test1.txt test2.txt abc abc def | jklm ghi | Ghi
「-c」オプションを指定すると、まず比較するファイル1、次に比較するファイル2の違っている部分の前後が表示されます。「-u」オプションを指定すると、比較する両者の内容がまとめて表示され、違っている部分のみが、別個に表示されます(筆者はこれが好みです)。「-y」では、両者の内容が横並びで表示されます(Terminal.appのウィンドウの幅によっては、見にくくなるかもしれませんね)。
場合によっては、大文字と小文字の違いは重要ではない場合もあるかと思います。そういう時は「-i」オプションを指定して大文字小文字の違いを無視させます。
[Macintosh:~/terminaltest] hiro% diff -ui test1.txt test2.txt --- test1.txt Sun Jan 5 02:02:44 2003 +++ test2.txt Sun Jan 5 02:03:02 2003 @@ -1,3 +1,3 @@ abc -def +jklm ghi
また、空白の行を無視させる場合には、「-B」を指定します。
[Macintosh:~/terminaltest] hiro% cat test1.txt abc def ghi [Macintosh:~/terminaltest] hiro% cat test3.txt abc def ghi [Macintosh:~/terminaltest] hiro% diff -u test1.txt test3.txt --- test1.txt Sun Jan 5 02:02:44 2003 +++ test3.txt Sun Jan 5 02:03:19 2003 @@ -1,3 +1,4 @@ abc def + ghi [Macintosh:~/terminaltest] hiro% diff -uB test1.txt test3.txt [Macintosh:~/terminaltest] hiro%
タブやスペースの数の違いを無視させる場合には、「-b」を指定します。
[Macintosh:~/terminaltest] hiro% cat test4.txt abc def g hi [Macintosh:~/terminaltest] hiro% cat test5.txt abc def g hi [Macintosh:~/terminaltest] hiro% diff -u test4.txt test5.txt --- test4.txt Sun Jan 5 02:03:59 2003 +++ test5.txt Sun Jan 5 02:10:54 2003 @@ -1,3 +1,3 @@ abc def - g hi + g hi [Macintosh:~/terminaltest] hiro% diff -ub test4.txt test5.txt [Macintosh:~/terminaltest] hiro%
test4.txtとtest5.txtでは3行目のgの前のタブの数とhの前のスペースの数を変えていますが、このように、違いを無視できます。ただし、タブや空白が入っているものと入っていないものを比較した場合は、このオプションを指定しても、下記のように、差があるものとして表示されます。
[Macintosh:~/terminaltest] hiro% diff -u test1.txt test4.txt --- test1.txt Sun Jan 5 02:02:44 2003 +++ test4.txt Sun Jan 5 02:03:59 2003 @@ -1,3 +1,3 @@ abc def -ghi + g hi [Macintosh:~/terminaltest] hiro% diff -ub test1.txt test4.txt --- test1.txt Sun Jan 5 02:02:44 2003 +++ test4.txt Sun Jan 5 02:03:59 2003 @@ -1,3 +1,3 @@ abc def -ghi + g hi
diffでディレクトリを指定し、その中に含まれるファイルを比較する事もできます。
[Macintosh:~/terminaltest] hiro% diff -u 1 2 diff -u 1/01.txt 2/01.txt --- 1/01.txt Sun Jan 5 01:55:49 2003 +++ 2/01.txt Sun Jan 5 01:56:21 2003 @@ -1,3 +1,3 @@ abc -def +jklm ghi Common subdirectories: 1/1 and 2/1
このように、中に含まれるファイルの差分を表示し、更に、同名のサブディレクトリがある場合には、Common subdirectories: 1/1 and 2/1と表示してくれます。
今回の例のように、同名のサブディレクトリがある場合には、「-r」オプションを指定する事で、サブディレクトリの中にあるファイルまで比較できます。
[Macintosh:~/terminaltest] hiro% diff -ur 1 2 diff -ur 1/01.txt 2/01.txt --- 1/01.txt Sun Jan 5 01:55:49 2003 +++ 2/01.txt Sun Jan 5 01:56:21 2003 @@ -1,3 +1,3 @@ abc -def +jklm ghi diff -ur 1/1/01.txt 2/1/01.txt --- 1/1/01.txt Sun Jan 5 01:55:49 2003 +++ 2/1/01.txt Sun Jan 5 01:56:21 2003 @@ -1,3 +1,3 @@ abc -def +jklm ghi
なお、何かが片方のディレクトリのみにある場合は、「Only in ディレクトリ : ファイル名またはディレクトリ名」という書式で表示されます。
さて、ここから話が少々ややこしくなります。パッチの作成とパッチ当てです。
パッチファイルの作成は「diff 更新前のファイル 更新後のファイル > パッチファイル」とdiffの結果をパッチファイルにリダイレクトしてやるだけですが、-uまたは-cオプションを指定しておくと、パッチを当てるファイルの指定までファイルの中に含める事ができて使い勝手が良くなります。また、diffで指定するファイルの順番を間違えると、逆の効果を持つパッチができてしまいますので要注意です。
[Macintosh:~/terminaltest] hiro% diff -u test1.txt test2.txt > patch.txt [Macintosh:~/terminaltest] hiro% cat patch.txt --- test1.txt Sun Jan 5 02:02:44 2003 +++ test2.txt Sun Jan 5 02:03:02 2003 @@ -1,3 +1,3 @@ abc -def -ghi +jklm +Ghi
このように、patch.txtにdiffの内容が、書き出されます。これを「patch < パッチファイル名」としてやることで、パッチを当てる事ができます。
[Macintosh:~/terminaltest] hiro% patch < patch.txt patching file test1.txt [Macintosh:~/terminaltest] hiro% cat test1.txt abc jklm Ghi
パッチを当てた結果、test1.txtが書き換えられました。
なお、カレントディレクトリ以外のディレクトリにあるファイルで「diff -u(or c) ディレクトリ/ファイル名 ディレクトリ/ファイル名 > パッチファイル」としてパッチを作成した場合(例えば、/Users/hiroでdiff -u Library/Preferences/.GlobalPreferences.plistとLibrary/Preferences/ModGlobalPreferences.txt > patch.txt)、patch < パッチファイル名でパッチを当てようとしたところ、ファイル名の指定を求められましたので、とりあえず、パッチを作成したいファイルのあるディレクトリで作業するようにした方が無難なようです。
いかがでしたでしょうか。筆者が思い付くところでは、ditto -rsrcForkで~/Library/Preferencesをどこかに複製し、初期設定を変更した際にどのファイルのどの場所に書き込まれるのかを解析するのが、一番面白い使い方ではないでしょうか。