これは、私がよく使用するアプローチです。
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