テックブログ

技術ネタ

diffコマンドについて

こんにちは、技術部のfuです。
今回は差分の確認を行うことができるコマンド、diffについて少し書いてみたいと思います。

なお、この記事の内容はCentOS 6.8でコマンドを実行し、その結果を記載しています。

まずは基本のファイル比較です。
以下のようなファイル、hogeとfugaがあったとします。

$ cat hoge
ringo
gorira
rappa
paseri
$ cat fuga
gorira
rakuda
paseri
ringo

変更元ファイル:hoge
変更先ファイル:fuga

として比較すると、

  • 1行目のringoを削除
  • 2行目(元ファイルは3行目)のrappaをrakudaに変更
  • 4行目にringoを追加

このように変更が行われています。
これを色々なオプションをつけてdiffしてみました。


まず、オプションをつけずにファイルの比較を行いました。

$ diff hoge fuga
1d0
< ringo
3c2
< rappa
---
> rakuda
4a4
> ringo

hogeと比較し、

  • 削除されている部分は <
  • 追加されている部分は >

といった形式で表示されます。
「rappa」→「rakuda」のように変更された箇所は、

  • 「rappa」が削除された為、<
  • 「rakuda」が追加された為、>

というような形となっています。


次に-uオプションをつけて比較を行いました。unified形式と呼ばれるようです。

$ diff -u hoge fuga
--- hoge        2017-09-05 05:11:46.693565839 +0900
+++ fuga        2017-09-05 05:16:11.586791985 +0900
@@ -1,4 +1,4 @@
-ringo
 gorira
-rappa
+rakuda
 paseri
+ringo

hogeと比較し、

  • 削除されている部分は –
  • 追加されている部分は +

といった形式で出力されます。
デフォルトでは変更箇所の前後3行が出力されますが、-U もしくは–unified=オプションを用いることにより、
前後の出力行数を変更することができます。但し、パッチとして利用する場合は少なくとも2行は必要なようです。


次に-cオプションをつけて比較を行いました。context形式と呼ばれるそうです。

$ diff -c hoge fuga
*** hoge        2017-09-05 05:11:46.693565839 +0900
--- fuga        2017-09-05 05:16:11.586791985 +0900
***************
*** 1,4 ****
- ringo
  gorira
! rappa
  paseri
--- 1,4 ----
  gorira
! rakuda
  paseri
+ ringo

hogeと比較し、

  • 削除されている部分は –
  • 追加されている部分は +
  • 変更されている部分は !

といった形式で出力されます。


次に-yオプションをつけて比較を行いました。side-by-side形式と呼ばれるそうです。

$ diff -y hoge fuga
ringo                                                         <
gorira                                                          gorira
rappa                                                         | rakuda
paseri                                                          paseri
                                                              > ringo

さらに–left-columnをつけると、変更点のみが右側に表示されるようになります。
-yオプションをつけないとオプションなしのdiffと結果が変わらないので注意が必要です。

$ diff -y --left-column hoge fuga
ringo                                                         <
gorira                                                        (
rappa                                                         | rakuda
paseri                                                        (
                                                              > ringo

また、-W あるいは –width=オプションをつけることで、出力時の幅を指定することができます。デフォルトは130です。

$ diff -y --width=25 hoge fuga
ringo       <
gorira          gorira
rappa       |   rakuda
paseri          paseri
            >   ringo

左端から右端までの文字数の為、あまりに少ない数を指定すると以下のように途中で途切れてしまい、
わかりづらくなってしまうので、文字が途切れない程度に適度な幅を指定すると良いでしょう。

$ diff -y --width=10 hoge fuga
ri  <
go      go
ra  |   ra
pa      pa
    >   ri

細かい変更箇所まで知る必要はないが、ファイルに差異があるかどうかだけ知りたい。
そんな時は-qオプションをつけると、差異があるかどうかだけ教えてくれます。

$ diff -q hoge fuga
ファイルhogeとfugaは違います

差異がない場合は何も返して来ません。

$ diff -q hoge piyo
$

何か一言欲しい場合は-sオプションをつけると、差異がない場合でもメッセージを返してくれます。

$ diff -qs hoge piyo
ファイルhogeとpiyoは同一

-sオプションだけだと、差異がない場合は上記メッセージが返されるだけですが、差異がある場合はオプションなしのdiffの結果が返されます。

$ diff -s hoge fuga
1d0
< ringo
3c2
< rappa
---
> rakuda
4a4
> ringo

以上がファイルの比較ですが、diffコマンドではディレクトリ同士の比較を行うことも可能です。


test1, test2というディレクトリを作成し、test1にはhogeとfugaのコピーを、test2にはhogeのコピーのみを置きました。
ディレクトリ構造としてはこのような形で作成しています。

$ LANG=C tree
.
|-- fuga
|-- hoge
|-- test1
|   |-- fuga
|   `-- hoge
`-- test2
    `-- hoge

2 directories, 5 files

2つのディレクトリを比較してみます。

$ diff test1/ test2/
test1/だけに発見: fuga

test2ディレクトリにはファイル「fuga」をコピーしなかった為、上記のような結果が出ました。
今度は「fuga」もtest2ディレクトリにコピーしてみます。

$ diff test1/ test2/
$

差異がなくなった為、何も出力されなくなりました。
-sオプションをつけると一つ一つ結果を教えてくれるようです。

$ diff -s test1/ test2/
ファイルtest1/fugaとtest2/fugaは同一
ファイルtest1/hogeとtest2/hogeは同一

次に、test2ディレクトリ内の「fuga」を変更してdiffを実行してみます。

$ diff test1/ test2/
diff test1/fuga test2/fuga
4a5
> gorira

オプションをつけずに実行すると、差異のあったファイルと変更箇所がそのまま出力されました。
細かい変更箇所は知る必要はないが差異があったことだけを知りたい場合は-qオプションをつけます。

$ diff -q test1/ test2/
ファイルtest1/fugaとtest2/fugaは違います

変更点のないファイルも出力したい場合はさらに-sオプションをつけます。

$ diff -sq test1/ test2/
ファイルtest1/fugaとtest2/fugaは違います
ファイルtest1/hogeとtest2/hogeは同一

ここでふと、通常のファイルとディレクトリを比較するとどうなるのか気になって試してみました。
ファイル「hoge」と、test1ディレクトリを比較してみます。

$ diff hoge test1/
$ echo $?
0

エラーが出るかと想定して打ちましたが、返り値も「変更点がない」という意味の0です。
-sオプションをつけて再度実行してみました。

$ diff -s hoge test1/
ファイルhogeとtest1/hogeは同一

どうやら、test1ディレクトリ内のファイル「hoge」と比較していたようです。
比較先のディレクトリに比較元のファイルが存在しない場合は、当然エラーが返ってきます。

$ diff piyo test1/
diff: test1/piyo: そのようなファイルやディレクトリはありません

ちなみに、diffコマンドにおける返り値は、

  • 0 だと「差異なし」
  • 1 だと「差異あり」
  • 2 だと「何らかのエラーが発生した」

となります。比較対象のファイルが存在しない場合などに2を返します。


余談ですが、日本語環境で–helpオプションを叩くと、

$ diff --help
--------------------------------------------------------------------
  -d  --minimal  できるだけがんばって、小さい差分を見つける。
--------------------------------------------------------------------

こんな記述がありました。なんだか和みますね。
但し、-dオプションは「より小さな差分を生成できる代わりに実行が遅くなる(非常に遅くなる場合もある)」ようなので、サイズの大きいファイルを比較する場合には注意が必要かもしれません。

CentOS標準のリポジトリで導入はできない為、詳細は割愛しますが[colordiff]という
diffの結果を色つきで出力できるコマンドも存在するようですので、興味がある方は導入してみるのもいいかもしれません。

とりとめのない内容の記事になってしまいましたが、今回はこれで失礼します。

実績数30,000件!
サーバーやネットワークなど
ITインフラのことならネットアシストへ、
お気軽にご相談ください