2つのディレクトリの再帰的な差分を実行できますが、特定のファイル名またはファイルタイプの述語に一致するファイルのみ(それぞれの場所で)を比較できる方法はありますか?
例えば。したい何かのように
diff -r dir-a dir-b -filenames *.Java, ivy.xml, build.xml
...またはそれ以上:
diff -r dir-a dir-b -filetype text
diff
と-exec diff
を使用した呪文でもうまくいくと思うので、find
の使用は必須ではありません(補完ファイルパスを生成する方法がわからないだけです)後者の場合)。
differ-r
このシェルスクリプトは、2つのディレクトリの再帰的な差分を実行できますが、(それぞれの場所で)特定のファイル名またはファイルタイプのパターンに一致するファイルのみを比較します。
#!/bin/bash
greenvid="\0033[32m"
resetvid="\0033[0m"
if [ $# -ne 3 ]
then
echo "Usage: compare files in two directories including subdirectories"
echo " $0 <source-dir> <target-dir> <pattern>"
echo "Example: $0 subdir-1 subdir-2 \"*.txt\""
exit
fi
cmd='for pathname do
greenvid="\0033[32m"
resetvid="\0033[0m"
echo -e "${greenvid}diff \"$pathname\" \"${pathname/'\"$1\"'/'\"$2\"'}\"${resetvid}"
diff "$pathname" "${pathname/'\"$1\"'/'\"$2\"'}"
done'
#echo "$cmd"
find "$1" -type f -name "$3" -exec bash -c "$cmd" bash {} +
ファイル:
$ find -type f
./1/ett.txt
./1/two.doc
./1/t r e.txt
./1/sub/only-one.doc
./1/sub/hello.doc
./1/sub/hejsan.doc
./differ-r2
./differ-r1
./differ-r
./2/ett.txt
./2/two.doc
./2/t r e.txt
./2/sub/hello.doc
./2/sub/hejsan.doc
使用法:
$ ./differ-r
Usage: compare files in two directories including subdirectories
./differ-r <source-dir> <target-dir> <pattern>
Example: ./differ-r subdir-1 subdir-2 "*.txt"
実行中differ-r
:
実行されたdiff
コマンドラインは緑色のテキストで出力され、一致しない場合はデフォルトのテキスト(次のスクリーンショットでは黒色に白色)で出力されます。
$ ./differ-r 1 2 "*.doc"
diff "1/two.doc" "2/two.doc"
diff "1/sub/only-one.doc" "2/sub/only-one.doc"
diff: 2/sub/only-one.doc: No such file or directory
diff "1/sub/hello.doc" "2/sub/hello.doc"
2d1
< world
diff "1/sub/hejsan.doc" "2/sub/hejsan.doc"
$ ./differ-r 1 2 "*.txt"
diff "1/ett.txt" "2/ett.txt"
2c2
< stabben
---
> farsan
diff "1/t r e.txt" "2/t r e.txt"
1c1
< t r e
---
> 3
$
$ ./differ-r 1 2 "*"
diff "1/ett.txt" "2/ett.txt"
2c2
< stabben
---
> farsan
diff "1/two.doc" "2/two.doc"
diff "1/t r e.txt" "2/t r e.txt"
1c1
< t r e
---
> 3
diff "1/sub/only-one.doc" "2/sub/only-one.doc"
diff: 2/sub/only-one.doc: No such file or directory
diff "1/sub/hello.doc" "2/sub/hello.doc"
2d1
< world
diff "1/sub/hejsan.doc" "2/sub/hejsan.doc"
$ ./differ-r 2 1 "*"
diff "2/ett.txt" "1/ett.txt"
2c2
< farsan
---
> stabben
diff "2/two.doc" "1/two.doc"
diff "2/t r e.txt" "1/t r e.txt"
1c1
< 3
---
> t r e
diff "2/sub/hello.doc" "1/sub/hello.doc"
1a2
> world
diff "2/sub/hejsan.doc" "1/sub/hejsan.doc"
rsync
フィルターあり違いを説明する出力を取得する必要がなく、どのファイルが異なるか欠落しているのか(rsync
がそれらをコピーするため)のみを知っている場合は、次のコマンドラインを使用できます。
rsync --filter="+ <pattern>" --filter="+ */" --filter="- *"--filter="- */" -avcn <source directory>/ <target directory>
$ rsync --filter="+ *.doc" --filter="+ */" --filter="- *" -avcn 1/ 2
sending incremental file list
./
sub/
sub/hello.doc
sub/only-one.doc
sent 276 bytes received 35 bytes 622.00 bytes/sec
total size is 40 speedup is 0.13 (DRY RUN)
sent 360 bytes received 41 bytes 802.00 bytes/sec
total size is 61 speedup is 0.15 (DRY RUN)
olle@bionic64 /media/multimed-2/test/test0/temp $ rsync --filter="+ *.txt" --filter="+ */" --filter="- *" -avcn 1/ 2
sending incremental file list
./
ett.txt
t r e.txt
sub/
sent 184 bytes received 29 bytes 426.00 bytes/sec
total size is 21 speedup is 0.10 (DRY RUN)
コメント行もディレクトリもないきれいな出力が必要な場合は、次のように出力をgrep
できます。
$ pattern="*.doc"; rsync --filter="+ $pattern" --filter="+ */" --filter="- *" -avcn 1/ 2 | grep "${pattern/\*/.\*}"
sub/hello.doc
sub/only-one.doc
rsync-diff
このワンライナーは、シェルスクリプトrsync-diff
のコアコマンドにすることができます。
#!/bin/bash
LANG=C
if [ $# -ne 3 ]
then
echo "Usage: compare files in two directories including subdirectories"
echo " $0 <source-dir> <target-dir> <pattern>"
echo "Example: $0 subdir-1 subdir-2 \"*.txt\""
exit
fi
pattern="$3"; rsync --filter="+ $pattern" --filter="+ */" --filter="- *" \
-avcn "$1"/ "$2" | grep "${pattern//\*/.\*}" | grep -v \
-e '/$' \
-e '^sending incremental file list$' \
-e '^sent.*received.*sec$' \
-e '^total size is.*speedup.*(DRY RUN)$'
シェルがサポートする コマンド置換 を使用すると、次のワンライナーを使用できます(@JammingThebBitsですでに注記されています)。
diff -r dir-a dir-b --exclude-from=<( \
find dir-a dir-b -type f -not \( -name '*.xml' -or -name '*.Java' \) \
| sed 's:^.*/\([^/]*\)$:\1:' \
)
これは次のように機能します。find
対象外のファイルを検索し、sed
ベース名を抽出します(多くのファイルがある場合、basename
の実行は非常に低速です)。 一時的なファイルでそれらを;このようなファイルはdiff
に渡され、比較から除外するように指示されます(二重除外=包含)。
コマンド置換がない場合は、sed
出力をファイルに入れて、明示的にdiff
に渡します。
XMLとJavaファイルのみを検索した例では、ORで区切って必要に応じて変更しています。