
次の問題に対する Linux ソリューションを探しています:
多数のファイルを含む 2 つのディレクトリがあります。すべてのファイル名はランダムで、両方のディレクトリで異なります。ただし、2 つのディレクトリ内の一部のファイルの内容は同じです。
両方のディレクトリにあるすべてのファイルを 3 番目のディレクトリにコピーします。(「両方にある」とは、名前が同じではなく、内容が同じであることを意味します。)
答え1
ファイル名に空白がなく、どちらのディレクトリにもサブディレクトリがないと仮定すると、次のようにすると、MD5 サムが一致するファイル名のペアが出力されます。
join -o 1.2,2.2 <(md5sum $D1/* | sort) <(md5sum $D2/* | sort)
ファイル名の 1 つだけを取得するには、-o 1.2
または を使用します-o 2.2
。
ファイル名 (またはパス) に空白が含まれる可能性がある場合は、より慎重に行う必要があります。
1 つのディレクトリに複数の名前を持つ同じファイルが存在する可能性がある場合は、さらに賢く対処する必要があり、正確に何をすべきかを決定する必要があります。 1 つの可能性としては、結合を行う前に重複をフィルター処理することが挙げられます。
join -o 1.2,2.2 <(md5sum $D1/* | sort | uniq -w16) \
<(md5sum $D2/* | sort | uniq -w16)
使ってはいけませんsum
sum
16 ビットのチェックサムを出力します。各ディレクトリに数百のファイルがある場合でも、16 ビットのチェックサムを比較すると誤検出が発生する可能性があります。 もmd5sum
絶対的に安全というわけではありませんが、128 ビットのチェックサムで衝突が発生する可能性はごくわずかです。 疑わしい場合、そして本当に重要な場合は、cmp
ファイルも次のようになります。
join -o 1.2,2.2 <(md5sum $D1/* | sort) <(md5sum $D2/* | sort) |
while read F1 F2; do
if cmp -s $F1 $F2; then
cp F1 $D3
fi
done
(繰り返しますが、ファイル名に空白が含まれている場合は機能しません。)
答え2
この疑似コードには、お気に入りのシェルを使用します。
cd D1; sum * | while read l; do echo "D1 $l"; done >/tmp/foo
cd D2; sum * | while read l; do echo "D2 $1"; done >>/tmp/foo
sort -n /tmp/foo | awk '
$1 == prev_cs { echo "cp $3 dest"}
/prev_cs = $1/
' | shell
必要に応じて、コピーを発行する前にawk出力を保存して確認することができます。
答え3
mpez0 の重複をコピーするための回答と同様に、これは機能する可能性があります。
find {tst1,tst2} -exec sum {} {} \; 2> /dev/null | sort | uniq