だから名前をfilename:hash
。
私がしたいことはただ組み合わせをfilename:hash
そのまま維持しながらハッシュを一致させ、ファイルが変更されなかったため、そのハッシュは再計算されません。
この操作の実行中にファイルを移動または削除する必要がありますが、ファイル名がツールuniq
に対して十分に「固有」ではないため、パイプを直接使用しても機能しません。
これを行う方法はありますか? awk、bashなどのposixツール以外のツールを使用しないか、リストまたはデータベースファイルを使用しませんか?
詳細:いいえ、これは技術的に重複しません。これ投稿とはい、最終目標は技術的に同じです(たとえば、他の投稿やここですでに説明した方法/シナリオを使用して重複したアイテムを削除または移動するなど)。
答え1
使用してくださいbash
(実際にはPOSIXツールではありませんが、明示的に言及したため):
#!/bin/bash
names=( *:* )
printf '%s\n' "${names[@]##*:}" | sort | uniq -c |
while read count hash; do
if [[ $count -gt 1 ]]; then
echo 'Would delete/move these:'
printf '%s\n' *:"$hash"
fi
done
これは:
、現在のディレクトリの文字を含むすべての名前を配列として収集しますnames
。パターンマッチング*:*
仮定ただ私たちは興味のあるファイルであり、そのような名前を持つ他のファイルはありません。
拡張すると、"${names[@]##*:}"
ハッシュ値のみを含むリストが生成され、それらをソートして計算するために使用されますsort | uniq -c
。
結果はcount
ループhash
として読み取られwhile read
、数が1より大きい場合はハッシュが重複していることがわかります。ハッシュが重複している場合、パターンは*:"$hash"
そのハッシュとすべての名前を一致させます。
削除したい場合みんな重複したハッシュがあるファイルの場合は、次のことができます。
rm -f ./*:"$hash"
ファイルの 1 つを保持するには、次のようにします。
dupnames=( ./*:"$hash" )
rm -f "${dupnames[@]:1}"
これにより、配列が一致dupnames
する名前に設定され、ファイルシステムから最初の配列を除くすべての項目が削除されます。
一部のデバッグ出力を有効にした状態で実行して使用できます。rm
障害のあるまず、これが実際に動作すると確信するまで:
#!/bin/bash
names=( *:* )
printf '%s\n' "${names[@]##*:}" | sort | uniq -c |
while read count hash; do
if [[ $count -gt 1 ]]; then
echo 'Would delete/move these:'
dupnames=( ./*:"$hash" )
echo rm -f "${dupnames[@]:1}"
fi
done
sh
上記のPOSIXバリアント:
#!/bin/sh
for name in *:*; do
printf '%s\n' "${name##*:}"
done | sort | uniq -c |
while read count hash; do
if [ "$count" -gt 1 ]; then
echo 'Would delete/move these:'
set -- ./*:"$hash"
shift
echo rm -f "$@"
fi
done
sort | uniq -c
次に削除された最後の変形の変形awk
:
#!/bin/sh
for name in *:*; do
printf '%s\n' "${name##*:}"
done |
awk ' { count[$0]++ }
END { for (hash in count) if (count[hash] > 1) print hash }' |
while read hash; do
echo 'Would delete/move these:'
set -- ./*:"$hash"
shift
echo rm -f "$@"
done
このawk
フラグメントはこの答えの他のフラグメントを置き換えることもできますが、最終sort | uniq -c
ループではカウントが1より大きいかどうかをテストする必要はなく、ハッシュ値のみを読み取ることができます。