ディレクトリ内のすべてのファイルの名前を、コンテンツではなくファイル名のmd5ハッシュに変更します。


11

私はlinux /コマンドラインを使用するのが初めてで、MySQLデータベースのMD5暗号化された名前と一致するように、10K +ファイル(一意の名前)の名前を暗号化する必要があります。
ファイルのディレクトリの名前を変更する方法とファイルのハッシュを取得する方法(mdsum?)拡張すなわち

mynicepicture.jpg > fba8255e8e9ce687522455f3e1561e53.jpg 

それは単純な名前変更またはmv行であるように見えますが、私はそれを理解することができません。
あなたの洞察に感謝します

PS私は探しているものに近いいくつかの例でPerl関数の使用を見てきましたが、それらをどこでどのように使用するのかわかりません。


3
ファイルの内容ではなく、ファイルからハッシュを取得してもよろしいですか?
Anthon

12
注:MD5ハッシュは暗号化デバイスではありません。MD5は暗号化ハッシュでさえありません。ハッシュは、任意のハッシュであり、データセットを数値に一方向に変換したものです。元に戻すことはできません。実際の暗号化は、いつでも元に戻すことができます(暗号化に使用されるキーが与えられた場合)。
クサラナンダ

1
fba8255e8e9ce687522455f3e1561e53のMD5ハッシュとは、ハッシュ化するmynicepicture前に拡張機能を削除する必要があるという意味ですか?
クサラナンダ

@dessertつまりmd5sum <<<"file name"file nameファイルを既存のものにするかどうかにかかわらず、既存のファイル名を指定する以外は文字列と見なされるため、権限受領者は存在しません。
αғsнιη

回答:


14

どのシェルを使用するかは言わなかったので、私はBashを想定しています。答えは他のシェルと連携するように調整する必要があります。

for i in *; do sum=$(echo -n "$i"|md5sum); echo -- "$i" "${sum%% *}.${i##*.}"; done

スクリプトのバージョン:

for i in *; do
  sum=$(echo -n "$i" | md5sum)
  echo -- "$i" "${sum%% *}.${i##*.}"
done

この単純なforループは、現在のディレクトリ内のすべてのファイルを取得し、その名前のmd5合計を計算して出力します。あなたは二を交換リネーム開始したい場合は、機能性をチェックするためにこれを使用echoすることによってmv

解説

  • echo -n "$i" | md5sum– ファイル拡張子(Piping)を含む完全なファイル名の md5合計を計算し、拡張子の変更を次のいずれかに削除します。echo -n "$i"

    ${i%%.*}
    sed 's/\..*//' <<< "$i"
    echo "$i" | sed 's/\..*//'
  • sum=$(…)– (コマンド置換)で出力を実行して保存します$sum

  • ${sum%% *}– 次のいずれかと同じように、最初のスペース(パラメータ置換)まですべてを出力します。

    $(sed 's/ .*//' <<< "$sum")
    $(echo "$sum" | sed 's/ .*//')
  • ${i##*.} –次のいずれかと同じように、最後のドット(パラメーター置換)の後のすべてを出力します。

    $(sed 's/.*\.//' <<< "$i")
    $(echo "$i" | sed 's/.*\.//')

別のフォルダにあるファイルの名前を再帰的に変更する必要がある場合findは、-execオプションとともに使用します。


6
#!/bin/bash

md5name () {
    local base=${1##*/}
    local ext=${base##*.}
    local dir=${1%/*}

    printf '%s' "${base%.$ext}" | md5sum |
    awk -v dir="$dir" -v ext="$ext" '{ printf("%s/%s.%s\n", dir, $1, ext) }'
}

dir=$HOME  # where your files are

for pathname in "$dir"/*; do
    test -f "$pathname" || continue
    echo mv "$pathname" "$( md5name "$pathname" )"
done

このbashスクリプトは、md5sumGNU coreutils のユーティリティを使用して、任意のパス名のベース名(sans拡張子)からMD5ハッシュを計算します。ヘルパー関数md5nameは実際の計算を行い、完全なパスと拡張子を持つ新しい名前を出力します。

md5name機能は、使用してawk指定したパス名の部分との結果から、新しい名前を組み立てますmd5sum

単独で使用されている関数の例:

$ md5name '/some/path/file name here.extension'
/some/path/c9e89fa443d16da4b96ea858881320c9.extension

... c9e89fa443d16da4b96ea858881320c9は、文字列のMD5ハッシュですfile name here

echo上部のスクリプトからを削除して、実際にファイルの名前を変更します。echoある時点でファイル名を元の名前に戻す必要がある場合は、元のスクリプトの出力を(インプレースで)ファイルに保存することをお勧めします。

これを一連のファイルで2回実行すると、MD5ハッシュのMD5ハッシュが計算され、スクリプトを実行するたびにどのファイルが何と呼ばれるかについて注意しない限り、元のファイル名は回復できなくなります。


参考までに、このawk部分は次のように置き換えることができます。「-」をキャプチャwhile read sum dummy ; do printf "%s/%s.%s\n' $dir $sum $ext ; done ;する必要がありdummyます。
ロバートベンソン

@RobertBensonその問題​​は、スペースを含むファイル名がめちゃくちゃになることです。
クサラナンダ

よかった。スペースを含むファイル名は悪です。私はawk自分自身を楽しんbashでおりsystem()、ユーティリティを使用するのではなく、少し時間がawk
Robert Benson

5

perlさんrename

find . -name '*.jpg' -type f -exec rename -n '
  BEGIN{use Digest::MD5 qw(md5_hex)}
  my ($dir, $name, $ext) = m{(.*)/(.*)\.(.*)}s;
  $_ = "$dir/" . md5_hex($name) . ".$ext"' {} +

-n幸せなときに削除 します)。


すごい!これは拡張子なしのファイル名のmd5合計を計算しますが、完全なファイル名はどうですか?OPは、それが必要かどうかにかかわらず、それが必要かどうかは明らかにしなかった。
デザート

1
彼はそれを言わなかった、しかし彼が与える例はまさにそれである。
ロバートベンソン

2

AWKアプローチについて:

find [Directory] -type f [various other find options] | 
     awk '{orig=$0; 
           match($0,/^.*\//,path); sub("^"path[0], "");
           match($0, /.[[^.]+$/,ext); sub(ext[0]"$", "");
           ("echo \"" $0 "\"|md5sum") | getline;
           com=sprintf("mv \"%s\" \"%s%s%s\"", orig, p[0], $1, ext[0]);
           print(com)
           }'

最新のfindコマンドは、入力にディレクトリを必要としない.ため、[ディレクトリ]は空白のままにすることができます。-type f唯一以来、便利であるファイル、見つかったmd5sumディレクトリの好きや実行中のディレクトリ名を変更していないが、良いアイデアではないでしょう。-iname pattern一部のファイルのみを使用する場合に使用します。たとえば-iname \*.dat、大文字と小文字が重要な場合は、の-name代わりに使用します-iname

match(...); sub(...)片は、ファイル名の部分を抽出し、入力文字列にそれらを交換します。パスと拡張子を繰り返す可能性のある文字列が置き換えられないようにするため、"^"および"$"が[pre / ap]で区切られていることに注意してください。

に置き換えprint(com)system(com)、実際に名前変更を実行します。

md5sum実際のファイルのを名前として使用したい場合はmd5sum、合計と入力ファイル名を出力するという事実を使用して、次のようなことを行うことができます。

 find -type f -exec md5sum '{}' ';' | 
     while read sum file ; do 
       [echo] mv "$file" "`dirname $file`/$sum".extension ; 
     done

while read sum file2つの引数の結果になりますmd5sumコマンド、および割り当てsumfile彼らとの変数を。にsumはスペースを入れてはならないので、はread正常に機能するはずです。

もちろん、[echo]実際に実行するときにを削除する必要がありますが、スクリプト化された変更をテストして実行前に検索をテストする場合は、常に良い方法です。

これはすべて、実行していることを前提としていbashます。また、これは1つの長い行として入力できます。

find -iname \*.jpg -exec md5sum '{}' ';' | while read sum file ; do mv "$file" "`dirname $file`/$sum".jpg ; done

1
これはファイルの内容をハッシュするように見えます。OPは名前を(拡張子なしで)ハッシュしたかった。
クサラナンダ

質問を完全に読んだら助かると思います。
ロバートベンソン

2

これは、私がよく使用するアプローチです。

ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \\`echo \1 \| md5sum \| cut -d' ' -f 1\\`.\2|" | sh -

「ls」コマンドは、テキスト行のストリームを生成します。「sed」コマンドは、パターンマッチングルールで各行を変換します。「sed」コマンドは「mv」コマンドを出力し、実行のためにシェル「sh」を介してパイプされます。「mv」コマンドのパラメーターは、ファイルの名前を変更する「mv oldfilename newfilename」のようなものです。最後のドットの前の部分を取得し、それを「md5sum」コマンドの入力にエコーし、出力からハッシュだけを取得するsedコマンドで新しいファイル名を作成します。

私のプロセスを歩いて、最初のファイルをリストします(最初の3行だけを表示するには、「head -n 3」)。

ls | head -n 3
    1000-26092016.xml
    1000-27092016.xml
    12312-28092016.xml

次に、sedによる変換について考えます(まだシェルを介して生成されたコマンドをパイプしていません)。

ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \1.\2|" | head -n 3
    mv 1000-26092016.xml 1000-26092016.xml
    mv 1000-27092016.xml 1000-27092016.xml
    mv 12312-28092016.xml 12312-28092016.xml

3つの一致パターンがあります。

^\(.*\)      = match from start-of-line up to a dot
\.           = matches a single dot
\([^\.]*\)$  = match 0-or-more non-dot chars from end of line

入力ファイル名を「mv filename NEWfilename」で置き換えるためにsedを使用したいのですが、シェルを介してコマンドをパイプしているので、次のようにmd5sumを取得するコマンドを生成できます。

echo "1000-26092016" | md5sum
    55b18a6b0add4a318b0079e18512b4e8  -

ハッシュだけを取得する

echo "1000-26092016" | md5sum | cut -d' ' -f 1
    55b18a6b0add4a318b0079e18512b4e8

UNIXシェルでは、バックティック演算子( `some_command`)を使用してサブコマンドを実行できます。たとえば、

echo "howdy date there"
    howdy date there
echo "howdy `date` there"
    howdy Fri Sep 15 18:39:00 IST 2017 there

mvコマンドに戻って、md5sumを取得するために、sedで「there」をbacktickコマンドに置き換えて「mv here there」を生成したいと思います。sed replace-string内の文字列は次のように始まります

ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 `echo \1 | md5sum | cut -d' ' -f 1`.\2|" | head -n 3
    mv 1000-26092016.xml     b026324c6904b2a9cb4b88d6d61c81d1.xml
    mv 1000-27092016.xml     b026324c6904b2a9cb4b88d6d61c81d1.xml
    mv 12312-28092016.xml    b026324c6904b2a9cb4b88d6d61c81d1.xml

しかし、sedが文字列を見る前にbackticked-commandが実行されているため、各ファイル名に同じハッシュを作成していることは明らかです。sedがバックティックを出力するようにbacktickコマンドを実行しているシェルを停止するには、スラッシュを(パイプ文字にも)追加する必要があるため、次のようにします。

ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2|" | head -n 3
    mv 1000-26092016.xml     `echo 1000-26092016 | md5sum | cut -d' ' -f 1`.xml
    mv 1000-27092016.xml     `echo 1000-27092016 | md5sum | cut -d' ' -f 1`.xml
    mv 12312-28092016.xml    `echo 12312-28092016 | md5sum | cut -d' ' -f 1`.xml

出力では、スペースの場合にファイル名を引用符で囲む必要があるため、

ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick
    mv "a trick€€ fíle nÁme.xml" "`echo a trick€€ fíle nÁme | md5sum | cut -d' ' -f 1`.xml"

だから、シェルを通してそれをパイプすることによって、これを試してみましょう:

ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick | sh -

うまくいきましたか?私は推測する:

echo "a trick€€ fíle nÁme" | md5sum
    629db9c3071928ba0746f18444713b65  -
ls 629db9c3071928ba0746f18444713b65*
    629db9c3071928ba0746f18444713b65.xml

これがクロスチェックのアプローチです。「ls」オプション「-i」を使用して、UNIXファイルシステムiノードを出力します(「mv」で変更されません):

ls -1i | sort -n > .before
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | sh -
ls -1i | sort -n > .after
cut -d' ' -f 1 .before | while read I ; do echo "mv'd \"`grep ${I} .before`\" to \"`grep ${I} .after`\"" | sed "s| *$I *||g" ; done | head -n 3
    mv'd "1000-26092016.xml" to "55b18a6b0add4a318b0079e18512b4e8.xml"
    mv'd "1000-27092016.xml" to "b1baa80d99d5edf85c8aeb98185dd440.xml"
    mv'd "12312-28092016.xml" to "2b2d692bd047b64c99f7b9161349d430.xml"

または、「貼り付け」コマンド( 'coreutils'パッケージ)を使用する

paste .before .after | head -n 3
    36703389 1000-26092016.xml  36703389 55b18a6b0add4a318b0079e18512b4e8.xml
    36703390 1000-27092016.xml  36703390 b1baa80d99d5edf85c8aeb98185dd440.xml
    36703391 12312-28092016.xml 36703391 2b2d692bd047b64c99f7b9161349d430.xml

0

私はその1行の答えが好きですが、ファイル名を解析するため、うまくいきません。私もそれをシャハッシュで少し上げました。

find -iname "*.jpg" -exec sha1sum '{}' ';' | while read sum file ; do mv -v "$file" "`dirname '$file'`/$sum".jpg ; done

私はそれもファイルを引き出して、コマンドが入力された場所のベースにそれらを置くと思います。

ありがとう。


1
私たちはおそらく あなたが基づいた答え参照する必要があります。
ジェフシャラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.