diff コマンドの基本
diff
コマンドは2つのファイルを行ごとに差分を確認するための Linux コマンドです。
2つのファイルパスを指定すれば差分がある行を表示できます。
$ diff [FILE1] [FILE2]
サンプルデータ
サンプルデータとして a.txt
と b.txt
の2ファイルを用意します。
a.txt
aaXa
cccc
dddd
eeee
ffff
gggg
hhhh
iiii
jjjj
kkkk
b.txt
aaaa
bbbb
cccc
dddd
eeee
GGGG
hhhh
iiii
jjjj
kkkk
差分表示の方式
-u: ユニファイド形式 (Unified format)
ユニファイド形式 (Unified format) – Wikipedia
最も広く使われるdiffの表示形式です。同じ文脈で比較できるファイルの差分を表示します。
-u
オプションを指定するとユニファイル形式で表示します。
$ diff a.txt b.txt -u
--- a.txt 2021-02-14 21:23:13.388019400 +0900
+++ b.txt 2021-02-14 21:07:26.211076200 +0900
@@ -1,9 +1,9 @@
-aaXa
+aaaa
+bbbb
cccc
dddd
eeee
-ffff
-gggg
+GGGG
hhhh
iiii
jjjj
@@ -1,9 +1,9 @@
となっている個所は、1行目から9行目までの範囲で変更箇所があるという意味です。その範囲での差分が直後のブロックで表示されています。
+
から始まる行は挿入行、-
から始まる行は削除行です。 (スペース)
から始まる行は変更なしの行です。
-U [行数]
で差分のある行の後ろ何行を合わせて表示するかを指定できます。デフォルト(-u
)だと3行になります。
試しに -U 0
とすると変更のあった差分が出た行だけが確認できます。ちょうど何行目に変更があったかが確認できます。
$ diff a.txt b.txt -U 0
--- a.txt 2021-02-14 21:23:13.388019400 +0900
+++ b.txt 2021-02-14 21:07:26.211076200 +0900
@@ -1 +1,2 @@
-aaXa
+aaaa
+bbbb
@@ -5,2 +6 @@
-ffff
-gggg
+GGGG
-y: 2カラム形式
2つのファイルを左右に並べて比較する形式です。-y
オプションで指定します。
1ファイル目、最初に指定したファイルが左に表示され、2ファイル目が右に表示されます。
-W [全体の幅数]
を併せて指定すれば見やすくなります。デフォルトだと130です。コンソールの表示が小さいと変な位置で改行されて見づらいかもしれません。
幅30の2列表示で差分を出力すると以下のようになります。
$ diff a.txt b.txt -y -W 30
aaXa | aaaa
> bbbb
cccc cccc
dddd dddd
eeee eeee
ffff | GGGG
gggg <
hhhh hhhh
iiii iiii
jjjj jjjj
kkkk kkkk
右列に |
となっている個所が変更がある行、>
となっている行が2ファイル目に追加された行、<
となっている行が1ファイル目に追加された行です。それ以外の行は差分なしの行です。
少ない行数だと見やすいですが、余り大きいサイズのファイルだと全行表示されて見づらいです。見やすくするためにいくつかのオプションが使えます。
--left-column
オプションを指定すると差分がない行は左列にだけ表示できます。
$ diff a.txt b.txt -y -W 30 --left-column
aaXa | aaaa
> bbbb
cccc (
dddd (
eeee (
ffff | GGGG
gggg <
hhhh (
iiii (
jjjj (
kkkk (
--suppress-common-lines
オプションを指定すると、差分行のみ表示できます。
$ diff a.txt b.txt -y -W 30 --suppress-common-lines
aaXa | aaaa
> bbbb
ffff | GGGG
gggg <
わかりやすいですが、差分のあった行番号が表示できないので同じようなデータが続くファイルだとわかりづらいかもしれません。
<: コマンドの出力結果を使って diff をとる
何かしらのコマンドを実行してその標準出力の結果を使って差分をとることも可能です。リダイレクトを使って次のように記述します。
$ diff <(コマンド1) <(コマンド2)
カッコ()
の中に好きなコマンドを入れて実行すればよいです。片方をファイル名にしてももちろんOKです。
例えば echo
で出力した内容で差分をとってみます。
$ diff <(echo a) <(echo b) -u
--- /dev/fd/63 2021-02-14 22:47:13.382567000 +0900
+++ /dev/fd/62 2021-02-14 22:47:13.384406300 +0900
@@ -1 +1 @@
-a
+b
いい感じに確認できました。
以下、echo
の結果を使って diff
コマンドの例を見ていきます。
差分の判定いろいろ
-i: 大文字小文字の区別を無視する
-i
(“) を指定すると大文字と小文字の違いを無視します。
# -i なし(大文字小文字を区別)
$ diff <(echo a) <(echo A) -u
--- /dev/fd/63 2021-02-14 22:48:28.416033600 +0900
+++ /dev/fd/62 2021-02-14 22:48:28.417033300 +0900
@@ -1 +1 @@
-a
+A
# -i あり(大文字小文字を区別しない)
$ diff <(echo a) <(echo A) -u -i
'a' と 'A' を区別しないようになっています。
-E: タブの展開を無視する
タブ文字を半角スペースに展開された結果を無視します。具体的にはタブ文字と半角スペース4つを同一として無視します。
$ diff -E <(echo -e "hoge\thoge") <(echo "hoge hoge")
$ diff -E -u <(echo -e "hoge\thoge") <(echo "hoge hoge")
--- /dev/fd/63 2021-02-14 22:57:54.473863600 +0900
+++ /dev/fd/62 2021-02-14 22:57:54.477864500 +0900
@@ -1 +1 @@
-hoge hoge
+hoge hoge
-Z: 末尾の改行を無視する
差分比較するときに末尾にスペースがあるかないかを無視して比較します。
$ diff -Z <(echo "hoge") <(echo "hoge ")
# 末尾のスペースを無視するので差分なし
-b: スペースの個数を無視する
連続するスペースの個数を無視します。1つだけだろうが2つ以上続こうが同じひとまとまりのスペースとして扱います。
$ diff -b <(echo -e "hoge hoge") <(echo "hoge hoge")
# スペースの個数を無視するので差分なし
-w: スペースをすべて無視する
比較対象の文字列からすべてのスペースを無視して比較します。
$ diff -w <(echo "h o g e") <(echo " hoge ")
# スペースをすべて無視するので差分なし
-B: 空行を無視する
比較対象からすべての空行を無視して比較します。
$ diff -B <(echo -e "\nhoge\n\n\n") <(echo -e "hoge\n")
# すべての空行を無視するので差分なし
-r: 再帰的にディレクトリの中身の diff をとる
-r
のオプションを付けてディレクトを差分をとる対象として指定すると、ディレクトリを再帰的に走査して差分を取得してくれます。
例えば以下のようなディレクトリ構成があったとして
.
├── a
│ ├── x.txt
│ ├── y.txt
│ └── z.txt
└── b
├── x.txt
└── y.txt
a/x.txt
と b/x.txt
の内容が異なるとします。以下のコマンドでディレクトリ a/
と b/
の差分を再帰的に取ってみます。
$ diff -r -u a/ b/
diff -r -u a/x.txt b/x.txt
--- a/x.txt 2021-02-15 00:03:28.708367900 +0900
+++ b/x.txt 2021-02-15 00:03:21.597556100 +0900
@@ -1 +1 @@
-x
+xxx
Only in a/: z.txt
こんな感じの出力でファイル内容の差分と、そもそもファイルが存在しない場合にその旨が出力されていることが確認できます。
その他オプションのいろいろ
差分確認のためのオプションがいろいろ用意されています。 diff --help
の内容を見てください。
以上です。
$ diff --help
Usage: diff [OPTION]... FILES
Compare FILES line by line.
Mandatory arguments to long options are mandatory for short options too.
--normal output a normal diff (the default)
-q, --brief report only when files differ
-s, --report-identical-files report when two files are the same
-c, -C NUM, --context[=NUM] output NUM (default 3) lines of copied context
-u, -U NUM, --unified[=NUM] output NUM (default 3) lines of unified context
-e, --ed output an ed script
-n, --rcs output an RCS format diff
-y, --side-by-side output in two columns
-W, --width=NUM output at most NUM (default 130) print columns
--left-column output only the left column of common lines
--suppress-common-lines do not output common lines
-p, --show-c-function show which C function each change is in
-F, --show-function-line=RE show the most recent line matching RE
--label LABEL use LABEL instead of file name and timestamp
(can be repeated)
-t, --expand-tabs expand tabs to spaces in output
-T, --initial-tab make tabs line up by prepending a tab
--tabsize=NUM tab stops every NUM (default 8) print columns
--suppress-blank-empty suppress space or tab before empty output lines
-l, --paginate pass output through 'pr' to paginate it
-r, --recursive recursively compare any subdirectories found
--no-dereference don't follow symbolic links
-N, --new-file treat absent files as empty
--unidirectional-new-file treat absent first files as empty
--ignore-file-name-case ignore case when comparing file names
--no-ignore-file-name-case consider case when comparing file names
-x, --exclude=PAT exclude files that match PAT
-X, --exclude-from=FILE exclude files that match any pattern in FILE
-S, --starting-file=FILE start with FILE when comparing directories
--from-file=FILE1 compare FILE1 to all operands;
FILE1 can be a directory
--to-file=FILE2 compare all operands to FILE2;
FILE2 can be a directory
-i, --ignore-case ignore case differences in file contents
-E, --ignore-tab-expansion ignore changes due to tab expansion
-Z, --ignore-trailing-space ignore white space at line end
-b, --ignore-space-change ignore changes in the amount of white space
-w, --ignore-all-space ignore all white space
-B, --ignore-blank-lines ignore changes where lines are all blank
-I, --ignore-matching-lines=RE ignore changes where all lines match RE
-a, --text treat all files as text
--strip-trailing-cr strip trailing carriage return on input
-D, --ifdef=NAME output merged file with '#ifdef NAME' diffs
--GTYPE-group-format=GFMT format GTYPE input groups with GFMT
--line-format=LFMT format all input lines with LFMT
--LTYPE-line-format=LFMT format LTYPE input lines with LFMT
These format options provide fine-grained control over the output
of diff, generalizing -D/--ifdef.
LTYPE is 'old', 'new', or 'unchanged'. GTYPE is LTYPE or 'changed'.
GFMT (only) may contain:
%< lines from FILE1
%> lines from FILE2
%= lines common to FILE1 and FILE2
%[-][WIDTH][.[PREC]]{doxX}LETTER printf-style spec for LETTER
LETTERs are as follows for new group, lower case for old group:
F first line number
L last line number
N number of lines = L-F+1
E F-1
M L+1
%(A=B?T:E) if A equals B then T else E
LFMT (only) may contain:
%L contents of line
%l contents of line, excluding any trailing newline
%[-][WIDTH][.[PREC]]{doxX}n printf-style spec for input line number
Both GFMT and LFMT may contain:
%% %
%c'C' the single character C
%c'\OOO' the character with octal code OOO
C the character C (other characters represent themselves)
-d, --minimal try hard to find a smaller set of changes
--horizon-lines=NUM keep NUM lines of the common prefix and suffix
--speed-large-files assume large files and many scattered small changes
--color[=WHEN] colorize the output; WHEN can be 'never', 'always',
or 'auto' (the default)
--palette=PALETTE the colors to use when --color is active; PALETTE is
a colon-separated list of terminfo capabilities
--help display this help and exit
-v, --version output version information and exit
FILES are 'FILE1 FILE2' or 'DIR1 DIR2' or 'DIR FILE' or 'FILE DIR'.
If --from-file or --to-file is given, there are no restrictions on FILE(s).
If a FILE is '-', read standard input.
Exit status is 0 if inputs are the same, 1 if different, 2 if trouble.
Report bugs to: bug-diffutils@gnu.org
GNU diffutils home page: <http://www.gnu.org/software/diffutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>
コメントを書く