Diesen Ansatz verwende ich oft.
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \\`echo \1 \| md5sum \| cut -d' ' -f 1\\`.\2|" | sh -
Der Befehl "ls" erzeugt einen Strom von Textzeilen. Der Befehl "sed" transformiert jede Zeile mit Mustervergleichsregeln. Der Befehl "sed" gibt einen Befehl "mv" aus, der dann zur Ausführung durch eine Shell "sh" geleitet wird. Die Parameter des Befehls "mv" entsprechen "mv oldfilename newfilename", wodurch die Datei umbenannt wird. Ich konstruiere den neuen Dateinamen mit einem sed-Befehl, der den Teil vor dem letzten Punkt übernimmt, ihn in die Eingabe des Befehls "md5sum" überträgt und dann nur den Hash aus seiner Ausgabe entnimmt.
Gehen Sie durch meinen Prozess und listen Sie zuerst die Dateien auf ('head -n 3', um nur die ersten 3 Zeilen zu sehen):
ls | head -n 3
1000-26092016.xml
1000-27092016.xml
12312-28092016.xml
Denken Sie dann an die Transformation mit sed (noch keine generierten Befehle durch eine Shell leiten)
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
Es gibt drei Übereinstimmungsmuster:
^\(.*\) = match from start-of-line up to a dot
\. = matches a single dot
\([^\.]*\)$ = match 0-or-more non-dot chars from end of line
Ich möchte sed verwenden, um einen Eingabedateinamen durch "mv Dateiname NEWfilename" zu ersetzen, aber da ich Befehle durch eine Shell leite, kann ich Befehle generieren, die die md5sum erhalten, wie folgt
echo "1000-26092016" | md5sum
55b18a6b0add4a318b0079e18512b4e8 -
um nur den Hash zu bekommen
echo "1000-26092016" | md5sum | cut -d' ' -f 1
55b18a6b0add4a318b0079e18512b4e8
In einer Unix-Shell können wir Backtick-Operatoren (`some_command`) verwenden, um beispielsweise einen Unterbefehl auszuführen
echo "howdy date there"
howdy date there
echo "howdy `date` there"
howdy Fri Sep 15 18:39:00 IST 2017 there
Zurück zum Befehl mv möchte ich, dass sed "mv here there" erzeugt, wobei "there" durch einen Backtick-Befehl ersetzt wird, um die md5sum zu erhalten. Die Saite innerhalb der sed replace-Saite beginnt so
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
Es wird jedoch eindeutig für jeden Dateinamen der gleiche Hash erstellt, da der Befehl backticked ausgeführt wird, bevor sed die Zeichenfolge sieht. Um zu verhindern, dass die Shell den Befehl backtick ausführt, damit sed die Backticks ausgibt, müssen wir Schrägstriche (auch dem Pipe-Zeichen) voranstellen, also noch einmal:
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
Für die Ausgabe müssen auch Dateinamen bei Leerzeichen angegeben werden
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"
Probieren wir es also aus, indem wir es durch eine Shell leiten:
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick | sh -
Hat es funktioniert ? ich vermute:
echo "a trick€€ fíle nÁme" | md5sum
629db9c3071928ba0746f18444713b65 -
ls 629db9c3071928ba0746f18444713b65*
629db9c3071928ba0746f18444713b65.xml
Hier ist ein Ansatz zur Gegenprüfung. Verwenden Sie die Option "-s" "-i", um den i-Knoten des Unix-Dateisystems auszugeben (der sich mit "mv" nicht ändert):
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"
Oder verwenden Sie den Befehl "Einfügen" (Paket '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