diff -rでディレクトリ同士を比較しつつ特定ファイル名の結果だけ表示

はじめに

ディレクトリ同士をdiffコマンドで再帰的に比較するときは、
diff -r <dir1> <dir2>みたいにしますよね。
その中で特定ファイル名の結果を除外したい場合は
diff -r -x <filename> <dir1> <dir2>みたいにすればOK。
参考: https://linuxjm.osdn.jp/html/gnumaniak/man1/diff.1.html

しかし!除外はできるくせに「特定ファイル名の結果だけを表示」ってのは
diffコマンドの機能としては存在しないようです。

-qオプション付きであれば、diff -qr <dir1> <dir2> | grep <filename>でOKだけど、
ファイルの中身までちゃんと見たいときはそうは行かない。

やりたくなる度に調べては「やっぱないよなー。。。」ってガッカリしてたんですが、
無いならシェルスクリプト組んでやれ!と思って作りました。

コード

実行権限を付けて保存して、こんな風に実行してみてください〜。
./tdiff.sh <dir1> <dir2> <target filename>

tdiff.sh
#!/usr/bin/env bash

# diffコマンド名(普通のdiffでもOK)
# diffCommand=diff
diffCommand=colordiff

# 第一引数がハイフンで始まったらそのままdiffのオプションに渡す
if [ "${1:0:1}" = "-" ]; then
  option="$1"
  shift
else
  option="-uN"
fi

if [ $# -lt 3 ]; then
  echo "Usage: $0 [<diff option>] <dir1> <dir2> <target filename>"
  exit 1
fi

# $1 $2はディレクトリ名、$3はdiffを取りたいファイル名
output=$(diff -qr $1 $2)
while read -r line; do
  string=$(echo "$line" | awk '{print $1}');
  if [ $(echo $string | grep -e 'Only') ]; then
    # 片方にしかファイルがない場合
    fileName=$(echo "$line" | awk '{print $4}');
    if [ $fileName != "$3" ]; then
      continue
    fi
    path=$(echo "$line" | awk '{print $3}' | sed -e "s/\:/\//");
    fromFile=${path/$1/$2/}/$fileName;
    toFile=${path/$2/$1/}/$fileName;
  else
    # 両方にファイルがある場合
    fromFile=$(echo "$line" | awk '{print $2}');
    toFile=$(echo "$line" | awk '{print $4}');
    fileName=$(basename "$toFile")
    if [ $fileName != "$3" ]; then
      continue
    fi
  fi

  $diffCommand $option $fromFile $toFile
done <<< "$output"

補足

僕は色付きが好きなのでcolordiffを指定してますが、
インストールされてなければエラーになるはずなので注意してください。

alias tdiff=~/hoge/fuga/tdiff.shみたいにエイリアス貼ると便利です。
スクリプト名tdiffは「targetable diff」って意味です。

謝辞

全部自力で書くのは時間かかりそうなので
似たようなことやってる人探したところ、
ディレクトリ間の差分ファイル一覧取得をbash scriptで実現させる
がとても参考になりました!
かなり流用させてもらいまして感謝感謝 :bow:

おわりに

実はシェル芸も大好きなので、もっと腕磨いてQiitaにもどんどん書きたいなーと思った所存です。
ではまた〜。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.