このページでは、ファイルの差分を表示するコマンド「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をどこかに複製し、初期設定を変更した際にどのファイルのどの場所に書き込まれるのかを解析するのが、一番面白い使い方ではないでしょうか。