Man On a Mission

システム運用屋が、日々のあれこれを記録していくブログです。情報処理技術者試験の話題多し。高度試験の攻略なども。最近はやや歴史づいてます…。

【Linux】diffコマンドで二つのファイルを比較する

以前、Windowsのファイル比較コマンドである、fcコマンドについて記事を書きました。

【Windows】fcコマンドで二つのファイルを比較する - Man On a Mission

今回は、Linuxにおけるファイル比較コマンド、diffについてです。
Linuxを使っている人は割とよく使うコマンドじゃないかと思ってたのですが、差異(差分)表示の見方がよくわからない、という人も結構いるようです。
(確かにとっつきにくい感があるので、無理もないかも。)
そこで、今回は簡単ながら使い方と差異表示の見方について説明したいと思います。

使い方

以下の書式となります。

diff [オプション] ファイル1 ファイル2
※ [オプション]は省略可能

なお、比較結果は標準出力に出力されます。

オプションは色々とあるのですが、今回はdiffの基本的な使い方にとどめますので、以下についてだけ説明します。

  • -u 違いのある箇所を1つにまとめて、-記号と+記号で変更箇所を示す(unified形式)
  • -c 違いのある箇所をファイルごとに出力し、!記号で変更箇所を示す(context形式)
  • -y 2カラム(二列)表示で出力する

詳細は後述。

なお、以下オプションをつけると、ファイルに相違があるかどうかだけ確認できます。
(差異部分の表示などは行いません。)

  • -q ファイルが違うかどうかだけを出力する

サンプルテキスト

さて、コマンドの書式を載せたので次はdiff実行結果の例を…と言いたいところですが、いきなり結果だけ載せると余計に分からなくなると思います。
そこで、サンプルテキストを二つ用意し、それらをdiffで比較して説明します。
周りくどいようですが、diffの差分表示は割とクセがあるので。

サンプルとして、以下の二つのテキストを用います。

a.txt

blue:USA
red:UK
black:Germany
crimson:Canada
orange:Japan
violet:Latin America
brown:Philippines
yellow:China
gold:France
silver:Italia
green:Mexico

b.txt

blue:USA
black:Germany
deathcrimson:Ecole
orange:Japan
violet:Latin America
brown:Philippines
yellow:China
gold:France
silver:Italia
green:Mexico
red=orange:Anglo-Japanese Alliance

差異部分は次の通り。

  • red(b.txtでは削除)
  • crimson(b.txtでは内容が変更されている)
  • red=orange(a.txtには無し。b.txtのみ存在する行)

それでは、比較してみましょう。

素のdiff

とりあえず、何のオプションも付けずに比較。

$ diff a.txt b.txt
2d1
< red:UK
4c3
< crimson:Canada
---
> deathcrimson:Ecole
11a11
> red=orange:Anglo-Japanese Alliance

以下、この差異表示について説明。

2d1
< red:UK

a.txtにあった「red:UK」が削除されたことを表しています。
最初の「2d1」は、数字が行数、「d」は削除(delete)を意味します。

ちなみに、「< red:UK」は、a.txtに「red:UK」という行がある、ということを示しています。
「<」は不等号記号ではなく、矢印だと思ってください。
diffコマンドではファイルを二つ指定しますが、この二つのファイルのあいだに「<」という矢印が入るイメージです。
矢印でa.txtを指し示し「a.txtではこうだった」と教えてくれてるわけですね。

4c3
< crimson:Canada
---
> deathcrimson:Ecole

a.txtとb.txtで、変更された行であることを表しています。
「4c3」について、数字は削除の時と同じく行数を表しています。a.txtの4行目とb.txtの3行目を比較しているわけです。「c」は変更(change)を意味します。

先ほど「<」が「a.txt」を指し示していることを説明しました。この変更点表示のケースでは「< crimson:Canada」ですので、「a.txtではcrimson:Canadaになっている」ということを意味しています。
もう片方の「> deathcrimson:Ecole」は、「b.txtではdeathcrimson:Ecoleになっている」ことを教えてくれています。

11a11
> red=orange:Anglo-Japanese Alliance

最後は、b.txtで追加されている部分です。
「8a8」の数字はもちろん行数、「a」は追加(add)を意味します。
「> red=orange:Anglo-Japanese Alliance」は、「b.txtではred=orange:Anglo-Japanese Allianceになっている」という意味です。

Unified形式でdiff

次に-uオプションをつけてみます。-uオプションはUnified形式で比較結果を出力します。標準との違いは以下の通り。

  • 差異のある箇所に加えてその前後の行も併せて表示(デフォルトでは3行。「-U 行数」で変更可。)
  • ファイルを指し示す「<」「>」は使われず、ファイル1を基準とした「+」「-」での差異表示となる
$ diff a.txt b.txt
--- a.txt    2017-07-30 16:20:30.416739896 +0900
+++ b.txt    2017-07-30 16:20:33.128739825 +0900
@@ -1,7 +1,6 @@
 blue:USA
-red:UK
 black:Germany
-crimson:Canada
+deathcrimson:Ecole
 orange:Japan
 violet:Latin America
 brown:Philippines
@@ -9,3 +8,4 @@
 gold:France
 silver:Italia
 green:Mexico
+red=orange:Anglo-Japanese Alliance

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

上記、最初の差異を例に取ると、「@@ -1,7 +1,6 @@」は、a.txtの1行目から7行分、b.txtでは1行目から6行分に該当する箇所が表示されていることを意味しています。
次の差異、「@@ -9,3 +8,4 @@」は、a.txtの9行目から3行分、b.txtでは8行目から4行分に街頭する箇所の表示を意味しています。

追加は「+」、削除は「-」と、直観的な表示になってますので、素のdiffよりは、わかりやすいんじゃないでしょうか。

context形式でdiff

次は-cオプション、context形式での出力です。

Unified形式と同様、差異のある箇所に加えてその前後の行も併せて表示します。
(デフォルトでは3行。「-C 行数」で変更可。)

また、ここが一番大きな違いですが、指定した2ファイルについて、それぞれのファイルを基準に差異を表示します。
内容が異なる行は行頭に「!」、追加された行は「+」、削除された行は「-」が付きます。

$ diff -c a.txt b.txt
*** a.txt    2017-07-30 16:20:30.416739896 +0900
--- b.txt    2017-07-30 16:20:33.128739825 +0900
***************
*** 1,7 ****
  blue:USA
- red:UK
  black:Germany
! crimson:Canada
  orange:Japan
  violet:Latin America
  brown:Philippines
--- 1,6 ----
  blue:USA
  black:Germany
! deathcrimson:Ecole
  orange:Japan
  violet:Latin America
  brown:Philippines
***************
*** 9,11 ****
--- 8,11 ----
  gold:France
  silver:Italia
  green:Mexico
+ red=orange:Anglo-Japanese Alliance

今までの差異表示と似たりよったりですので、そろそろ慣れてきたのではないでしょうか。

上記例、最初の差異を例に取ると、「*** 1,7 ****」から始まる一連の行が、a.txtの1行目から7行分の表示と相違部分。
「--- 1,6 ----」から始まる一連の行がb.txtの1行目から6行分の表示と相違部分となっています。

さらに分かりやすく2カラム表示

-yオプションをつけると、双方のテキストを二列形式で表示できます。

$ diff -y a.txt b.txt
blue:USA							blue:USA
red:UK							      <
black:Germany							black:Germany
crimson:Canada						      |	deathcrimson:Ecole
orange:Japan							orange:Japan
violet:Latin America						violet:Latin America
brown:Philippines						brown:Philippines
yellow:China							yellow:China
gold:France							gold:France
silver:Italia							silver:Italia
green:Mexico							green:Mexico
							      >	red=orange:Anglo-Japanese Alliance

これに関しては説明は不要でしょう。
(なお、長いテキストファイルの比較ではかえって見づらいと思います。)

colordiff

ついでにもう一つ。比較結果に色付けしてくれるcolordiffというコマンドがあります。
可能なら、こちらを使ったほうが見やすいです。

インストー

debian

# apt-get install colordiff

RHEL

# yum install colordiff

使い方はいっしょ。

$ colordiff a.txt b.txt
2d1 < red:UK 4c3 < crimson:Canada --- > deathcrimson:Ecole 11a11 > red=orange:Anglo-Japanese Alliance

最後に

さて、diffコマンドの比較結果表示を中心に書いてみました。
正直、vimdiffとか使えるなら、そっちの方が便利かもしれません。

なお、どうでもいいのですが今回用意したサンプルテキストは、前回記事からの名残で、昔々にアメリカが策定した戦争計画「カラープラン」の各国への色割り当てとなっています*1
いや、本当、驚くくらいにどうでもいいのですが。

 

 

*1:一部抜粋して利用しているだけで全数ではありません。