ファイル名の1つのインスタンスのみを部分的に一致させるには?

ファイル名の1つのインスタンスのみを部分的に一致させるには?

だから名前を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より大きいかどうかをテストする必要はなく、ハッシュ値のみを読み取ることができます。

関連情報