私はlinux /コマンドラインを使用するのが初めてで、MySQLデータベースのMD5暗号化された名前と一致するように、10K +ファイル(一意の名前)の名前を暗号化する必要があります。
ファイルのディレクトリの名前を変更する方法とファイルのハッシュを取得する方法(mdsum?)を見てきましたが、ハッシュのハッシュを取得する方法にこだわっていますファイル名、拡張子を保持する生成されたハッシュにそのファイルの名前を変更します。
mynicepicture.jpg > fba8255e8e9ce687522455f3e1561e53.jpg
それは単純な名前変更またはmv
行であるように見えますが、頭を悩ませることはできません。
あなたの洞察に感謝します
PS私が探しているものに近いいくつかの例でPerl関数の使用を見てきましたが、それらをどこでどのように使用するかわかりません。
使用するシェルを指定しなかったため、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合計を計算して出力します。これを使用して機能を確認します。名前の変更を開始する場合は、2番目のecho
をmv
に置き換えます。
_echo -n "$i" | md5sum
_ –ファイル拡張子( Piping )を含む完全なファイル名のmd5合計を計算し、拡張機能_echo -n "$i"
_を次のいずれかに変更します。
_${i%%.*}
sed 's/\..*//' <<< "$i"
echo "$i" | sed 's/\..*//'
_
sum=$(…)
– _…
_を実行し、出力を_$sum
_に保存します( Command Substitution )
_${sum%% *}
_ –次のいずれかと同じように、最初のスペース( Parameter Substitution )まですべてを出力します。
_$(sed 's/ .*//' <<< "$sum")
$(echo "$sum" | sed 's/ .*//')
_
_${i##*.}
_ –次のいずれかと同様に、最後のドット(パラメーター置換)の後のすべてを出力します。
_$(sed 's/.*\.//' <<< "$i")
$(echo "$i" | sed 's/.*\.//')
_
別のフォルダーにあるファイルの名前を再帰的に変更する必要がある場合は、find
を_-exec
_オプションとともに使用します。
#!/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
スクリプトは、GNU coreutilsからのmd5sum
ユーティリティを使用して、任意のパス名のベース名(sans拡張子)からMD5ハッシュを計算します。ヘルパー関数md5name
は実際の計算を行い、完全なパスと拡張子を付けて新しい名前を出力します。
md5name
関数はawk
を使用して、指定されたパス名の一部とmd5sum
の結果から新しい名前を組み立てます。
単独で使用されている関数の例:
$ md5name '/some/path/file name here.extension'
/some/path/c9e89fa443d16da4b96ea858881320c9.extension
...ここで、c9e89fa443d16da4b96ea858881320c9
は、文字列file name here
のMD5ハッシュです。
上部のスクリプトからecho
を削除して、実際にファイルの名前を変更します。ある時点でファイル名を元の名前に復元する必要がある場合は、元のスクリプトの出力をファイルに保存する(echo
を適切な場所に)ことができます。
このtwiceを一連のファイルで実行すると、MD5ハッシュのMD5ハッシュが計算され、元のファイル名は、ファイルを呼び出すたびにどのファイルが呼び出されるかについて注意を払わない限り、回復できなくなります。脚本。
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
幸せなとき)。
これは、私がよく使用するアプローチです。
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コマンドで新しいファイル名を作成します。
プロセスを歩いて、最初のファイルをリストします( 'head -n 3'で最初の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
Sedを使用して入力ファイル名を「mv filename NEWfilename」に置き換えたいのですが、シェルを介してコマンドをパイプ処理しているので、次のように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が実行されているため、各ファイル名に同じハッシュを作成していることは明らかです。シェルがbacktickコマンドの実行を停止してsedがバックティックを出力するようにするには、スラッシュを(パイプ文字にも)追加する必要があるため、次のようにします。
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
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 file
_は、_md5sum
_コマンドの結果である2つの引数を取り、sum
およびfile
変数をそれらに割り当てます。 sum
にはスペースを入れてはならないので、read
は正常に機能します。
明らかに_[echo]
_は実際に実行するときに削除する必要がありますが、スクリプト化された変更をテストして実行前に検索をテストする場合は常に良い方法です。
これはすべて、bash
を実行していることを前提としています。また、これは1つの長い行として入力できます。
_find -iname \*.jpg -exec md5sum '{}' ';' | while read sum file ; do mv "$file" "`dirname $file`/$sum".jpg ; done
_
私はその1行の答えが好きですが、ファイル名を解析するので壊れます。私もそれをシャハッシュで少し上げました。
find -iname "*.jpg" -exec sha1sum '{}' ';' | while read sum file ; do mv -v "$file" "`dirname '$file'`/$sum".jpg ; done
私はそれもファイルを引き出して、コマンドが入力された場所のベースにそれらを置くと思います。
ありがとう。