Questo approccio mi piace spesso usare.
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \\`echo \1 \| md5sum \| cut -d' ' -f 1\\`.\2|" | sh -
Il comando "ls" produce un flusso di righe di testo. Il comando "sed" trasforma ogni riga con regole di corrispondenza del modello. Il comando "sed" genera un comando "mv" che viene quindi reindirizzato attraverso una shell "sh" per l'esecuzione. I parametri del comando "mv" sono come "mv oldfilename newfilename", che rinomina il file. Costruisco il nuovo nome-file con un comando sed che prende la parte prima dell'ultimo punto e lo fa eco nell'input del comando "md5sum", quindi prende solo l'hash dal suo output.
Seguendo il mio processo, elenco dei primi file ('head -n 3' per vedere solo le prime 3 righe):
ls | head -n 3
1000-26092016.xml
1000-27092016.xml
12312-28092016.xml
Quindi pensa a trasformarti con sed (non eseguire il piping di alcun comando generato attraverso una shell)
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
Esistono tre modelli di corrispondenza:
^\(.*\) = match from start-of-line up to a dot
\. = matches a single dot
\([^\.]*\)$ = match 0-or-more non-dot chars from end of line
Voglio usare sed per sostituire un nome file di input con "mv nomefile NEWfilename", ma mentre eseguo il piping dei comandi attraverso una shell, posso generare comandi che ottengono il md5sum, come questo
echo "1000-26092016" | md5sum
55b18a6b0add4a318b0079e18512b4e8 -
per ottenere solo l'hash
echo "1000-26092016" | md5sum | cut -d' ' -f 1
55b18a6b0add4a318b0079e18512b4e8
In una shell unix, possiamo usare operatori backtick (`some_command`) per eseguire un comando secondario, quindi per esempio
echo "howdy date there"
howdy date there
echo "howdy `date` there"
howdy Fri Sep 15 18:39:00 IST 2017 there
Tornando al comando mv, voglio che sed produca "mv here there" con "there" sostituito con un comando backtick per ottenere md5sum. La stringa all'interno della stringa di sostituzione sed inizia in questo modo
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
Ma sta chiaramente creando lo stesso hash per ogni nome file, dato che il comando backticked viene eseguito prima che sed veda la stringa. Per impedire alla shell di eseguire il comando backtick in modo che sed emetta i backtick, dobbiamo anteporre barre (anche al carattere pipe), quindi di nuovo:
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
L'output ha anche bisogno di nomi di file da quotare in caso di spazi, quindi
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"
Quindi proviamo questo, eseguendo il piping attraverso una shell:
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick | sh -
Ha funzionato ? suppongo:
echo "a trick€€ fíle nÁme" | md5sum
629db9c3071928ba0746f18444713b65 -
ls 629db9c3071928ba0746f18444713b65*
629db9c3071928ba0746f18444713b65.xml
Ecco un approccio al controllo incrociato; usa l'opzione "ls" "-i" per generare l'i-node del filesystem unix (che non cambia con "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"
Oppure, usando il comando "incolla" (pacchetto '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