Bashシェルスクリプトで2つのディレクトリを比較し内容に差異があったファイル名を一覧表示する

2023-03-27Bash

はじめに

diff コマンドを使えば 2 つのファイルの内容の差分を確認することができます。

$ seq 1 3 > 1.txt

$ seq 2 4 > 2.txt

$ diff 1.txt 2.txt
--- 1.txt       2021-04-26 21:35:52.000000000 +0900
+++ 2.txt       2021-04-26 21:35:58.000000000 +0900
@
$ diff 1.txt 2.txt
1d0
< 1
3a3
> 4

diff コマンドには、2 つのファイルだけではなく、2 つのディレクトリの中にあるすべてのファイルに対して差分を確認する機能もあります。 ( ex: diff -r dir1/ dir2 )

diff -r
ではファイルのコンテンツ差分がすべて表示されますが、
差分のあったファイルの名前だけが欲しい 場合はどうしたら良いでしょうか?

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ head -n 2 /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

diff -r を使ってディレクトリ間のファイルの差分を出力

diff -r コマンドについておさらいです。

diff -r を使って、2 つのディレクトリに格納されているファイルの差分を表示してみます。

挙動を確認するために、適当なディレクトリ階層とファイルを用意します。

# ディレクトリを作成
$ mkdir -p dir1/a dir1/b dir1/c/d

# 1.txt から 4.txt まで4つのファイルを作成
$ seq 1 10 > dir1/a/1.txt

$ seq 1 20 > dir1/b/2.txt

$ seq 1 30 > dir1/c/d/3.txt

$ seq 1 40 > dir1/4.txt

# フォルダ階層を表示
$ tree
.
└── dir1
    ├── 4.txt
    ├── a
    │   └── 1.txt
    ├── b
    │   └── 2.txt
    └── c
        └── d
            └── 3.txt

5 directories, 4 files

dir1 というディレクトリが用意されました。

次に、 dir1 ディレクトリをコピーして dir2 ディレクトリを作成します。

$ cp -a dir1 dir2

内容は全く同じです。

ここで dir1 ディレクトリのファイルをいくつか書き換えてみます。

# 1.txt の1行目を削除
$ sed -i 1d dir1/a/1.txt

# 2.txt の最終行に追記
$ echo ADDED >> dir1/b/2.txt

# 4.txt を削除
$ rm -f dir1/4.txt

diff -r でディレクトリ間の差分を確認してみます。

$ diff -r dir1 dir2
Only in dir2: 4.txt
diff -r dir1/a/1.txt dir2/a/1.txt
0a1
> 1
diff -r dir1/b/2.txt dir2/b/2.txt
21d20
< ADDED

想定通りに差分が表示されました。

  • 4.txt は dir2 にしか無い
  • 1.txt の 1 行目に差分
  • 2.txt の最終行に差分

diff -r --brief を使ってディレクトリ間の差分のあるファイル名のみを出力

今度は差分内容ではなく、 差分のあるファイルの名前だけを出力 させてみたいと思います。

先程の -r オプションに加えて、 --brief
オプションを付与すると、差分があるファイル名のみが表示されます。

$ diff -r --brief dir1/ dir2/
Only in dir2/: 4.txt
Files dir1/a/1.txt and dir2/a/1.txt differ
Files dir1/b/2.txt and dir2/b/2.txt differ

--new-file オプションについて

4.txtdir1 ディレクトリに存在しないため、 1.txt2.txt
とは異なった表示のされ方をしています。
表示のされ方を合わせるためには --new-file オプションを付与します。

$ diff -r --brief --new-file dir1/ dir2/
Files dir1/4.txt and dir2/4.txt differ
Files dir1/a/1.txt and dir2/a/1.txt differ
Files dir1/b/2.txt and dir2/b/2.txt differ

--new-file オプションですが、注意しないといけないことがあります。

中身が空のファイル( ex: .gitkeep )が存在していた場合、 --new-file
オプションを付けると差分から無視されてしまいます。

# からファイルを作成
$ touch dir1/5.txt

# 差分を確認してみる
$ diff -r --brief --new-file dir1/ dir2/
Files dir1/4.txt and dir2/4.txt differ
Files dir1/a/1.txt and dir2/a/1.txt differ
Files dir1/b/2.txt and dir2/b/2.txt differ

--new-file オプションを付与しなければ、先程作成した 5.txt
も差分として表示されます。

$ diff -r --brief dir1/ dir2/
Only in dir2/: 4.txt
Only in dir1/: 5.txt
Files dir1/a/1.txt and dir2/a/1.txt differ
Files dir1/b/2.txt and dir2/b/2.txt differ

空のファイルを意図的に無視したい場合には便利なオプションですが、そうでない場合には注意が必要です。

ひとこと

diff -r --brief
オプションを付与しても、出力される情報はファイル名以外のメッセージも表示されるため、厳密にファイル名のみが欲しい場合にはメッセージを切り取る手間が必要です。

2023-03-27Bash