Linux環境で実行するスクリプトを作成しようとしています。
.jpeg
ディレクトリツリーでファイルを見つけ、名前付きディレクトリにコピーしますjpegs
。
重複したファイル名を表示したいのですが、エラーのみを表示するのではなく、生成されたリストに重複したファイル名を1回だけリストして同じ名前を2回表示しません。
これはこれまで私のスクリプトです。
#!/bin/sh
if ! mkdir jpegs 2> /dev/null
then
echo " Cannot create directory \"jpegs\" perhaps it already exists."
echo " delete the directory and try again."
exit
fi
for srcpath in $(find fs282/mirror -iname "*.jpg")
do
cp --backup $srcpath jpegs/
done
echo "List of Duplicate Files Follows"
答え1
出力を繰り返さないでくださいfind
。これはエレガントではなく(ループはすべてのパス名が見つかるまで最初の繰り返しを開始しません)、危険です(見つかったパス名はスペース、タブ、および改行に分割され、シェルはファイル名のワイルドカードパターンに拡張しようとします。 )。
代わりに(名前の競合がある場合は、見つかったファイルをコピーしたくないとします):
find fs282/mirror -type f -iname '*.jpeg' -exec sh -c '
for pathname do
if [ -e "jpegs/${pathname##*/}" ]; then
printf "%s\n" "${pathname##*/}"
else
cp "$pathname" jpegs/
fi
done' sh {} + | sort -u
find
インラインシェルスクリプトのパス名ジェネレータとして使用されます。find
見つかったパス名はスクリプトに渡され、.NETの各パス名を使用してそのパス名を繰り返します$pathname
。このスクリプトはパス名のファイル名部分がディレクトリにあるかどうかをテストしjpegs
、そうであればパス名の末尾にファイル名を標準出力として出力します。ファイル名がない場合、jpegs
ファイルはコピーされます。
パラメータ置換は${pathname##*/}
最初から$pathname
最後まで文字を削除します/
。 ] 末尾のファイル名部分を除いて。
最後に、sort -u
インラインスクリプトで印刷されたすべてのファイル名を取得し、重複を削除しながらソートします。
別の方法:
find fs282/mirror -type f -iname '*.jpeg' \
! -exec sh -c '[ -e "jpegs/${1##*/}" ] && printf "%s\n" "${1##*/}"' sh {} ';' \
-exec cp {} jpegs ';' | sort -u
本質的に同じ内容ですが、まったく異なって表現されます。
短いインラインシェルスクリプトを使用してファイル名が下にあるかどうかをテストしjpegs
、その場合はファイル名を印刷して後でソートしてから、find
次のファイルに進みます。存在しない場合はファイルがコピーされます。
関連: