web-dev-qa-db-ja.com

sha1sumのランダムな文字でファイルの名前を変更します。名前は一意ですか?

このコマンドを使用して、sha1sumのランダムな文字でファイルの名前を変更し、すべてのファイルをサブディレクトリから現在のディレクトリに移動します。

for fname in `find . -type f`; do mv "$fname" $(echo "$fname" | sha1sum | cut -f1 -d' ').html; done
  1. しかし、問題は、一意のファイル名を作成するかどうかです。 sha1sumから生成された名前が一意ではない(2回以上生成された)のではないかと心配しています。
  2. 上記のコマンドを実行してから、別のディレクトリで別のコマンドを実行すると、ファイルごとに一意のファイル名が生成されますか?
2

sha1sum出力は、入力が一意である限り一意になります。 (非常に不運で、sha1sumの衝突を見つけた場合を除きます)。

ユースケースについて:printf '%s' "$fname"の代わりにecho "$fname"を使用するのは良い習慣です。前者は、$fname-n、または-e、…の場合に機能します。 enzotib remark も参照してください。一見それを見逃しました。

また、あなたの動機は正確にはわかりませんが、ファイル名ではなくファイルの内容をsha1sumに提供することを検討してください。このようにして、一意のコンテンツごとに一意のファイル名を取得します。

2

まず、いくつかのシェルが重要です。

  • _for fname in `find …`_を使用しないでください。ファイル名が壊れ、名前が長すぎるファイルが多すぎると失敗します(コマンドラインが長すぎるため)。代わりに_find -exec_を使用してください。 findによって実行されるコマンドでシェル拡張が必要な​​ため、 シェルを呼び出す
  • コマンド置換と変数置換(_"$fname"_、"$(echo …)")を二重引用符で囲む必要があります。
  • echoは、いくつかのシェルでバックスラッシュをマングルします(_-_で始まるいくつかの引数もマングルしますが、すべての引数は_./_で始まるため、ここでは問題になりません)。文字列を文字通りに出力する方法は、_printf "%s\n" "$fname"_、または_printf "%s"_ "$ fname"で、最後の改行を回避します。ここでは、ファイル名のハッシュとは対照的に、ファイル名のハッシュと最後の改行を取得する理由はありません。

したがって、次のコマンドを取得します。

_find . -type f -exec sh -c 'mv "$0" "$(printf "%s" "$0" | sha1sum | cut -f1 -d" ").html' {} \;
_

名前のバッチ全体に対して一度にシェルを呼び出す方が少し速くなります。

_find . -type f -exec sh -c 'for fname; do mv "$fname" "$(printf "%s" "$fname" | sha1sum | cut -f1 -d" ").html; done' _ {} +
_

この方法の問題は、mvがディレクトリのトラバースを終了する前にfindが動作を開始した場合、移動されたファイルがmvによって取得される可能性があることです。コマンドはファイルの移動を開始する前にfindが終了するのを待つため、これはコマンドの問題ではありません。したがって、名前を変更したファイルを別のディレクトリ階層に配置します。これにより、提案されたコマンドにもある別の問題が解決されます。つまり、mvは、たまたま_<sha1sum>.html_と呼ばれる既存のファイルを上書きする可能性があります。

_mkdir ../staging
find . -type f -exec sh -c 'for fname; do mv "$fname" ../staging/"$(printf "%s" "$fname" | sha1sum | cut -f1 -d" ").html; done' _ {} +
find . -depth \! -name "." -type d -exec rmdir {} +
mv ../staging/* .
_

次に、主な質問に移ります。パスが異なる2つのファイルは、2つの異なるSHA-1ハッシュにマップされます。数学的に言えば、同じSHA-1ハッシュを持つ別個の文字列が存在します(文字列は無限にありますが、ハッシュは有限であるため、これは明らかです)。ただし、実際には、それらを見つける方法は誰にもわかりません。SHA-1の既知の衝突はありません。将来、SHA-1が破損する可能性があります。その場合、手順は偶発的な衝突に対してのみ安全であり、悪意のある攻撃者に対しては安全ではありません。それが発生した場合(すぐには発生しません)、その時点で安全なハッシュアルゴリズムと見なされているものにアップグレードする必要があります。

2番目の質問については、ハッシュはハッシュする文字列によって完全に決定されます。したがって、_tweedledum/staple_と_tweedledee/staple_という2つのファイルがあり、各ディレクトリtweedledeetweedledumからその名前変更手順を順番に実行すると、両方のディレクトリは次のようになります。 _1c0ee9c1eed005a476403c7651b739ae5bc7cf2a.html_というファイル。別の名前を付けたい場合は、ディレクトリの名前など、ハッシュ化されたテキストにいくつかの識別可能なコンテンツを含める必要があります。

まず第一に私は代用することを提案します

for fname in `find . -type f`; do

find . -type f | while read -r fname; do

次に、sha1sumに関しては、「実質的に」一意である必要があります。つまり、かなり低い場合に同じチェックサムで異なるファイルを使用する可能性があり、安全に一意であると見なすことができます。

1
enzotib