Essa abordagem geralmente gosto de usar.
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \\`echo \1 \| md5sum \| cut -d' ' -f 1\\`.\2|" | sh -
O comando "ls" produz um fluxo de linhas de texto. O comando "sed" transforma cada linha com regras de correspondência de padrões. O comando "sed" gera um comando "mv" que é então canalizado através de um shell "sh" para execução. Os parâmetros do comando "mv" são como "mv oldfilename newfilename", que renomeia o arquivo. Eu construo o novo nome de arquivo com um comando sed que toma a parte antes do último ponto e o ecoa na entrada do comando "md5sum" e, em seguida, pega apenas o hash da saída.
Percorrendo meu processo, primeiro liste os arquivos ('head -n 3' para ver apenas as 3 primeiras linhas):
ls | head -n 3
1000-26092016.xml
1000-27092016.xml
12312-28092016.xml
Em seguida, pense em transformar com sed (ainda não canalizando nenhum comando gerado por meio de um 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
Existem três padrões de correspondência:
^\(.*\) = match from start-of-line up to a dot
\. = matches a single dot
\([^\.]*\)$ = match 0-or-more non-dot chars from end of line
Eu quero usar sed para substituir um nome de arquivo de entrada por "mv filename NEWfilename", mas como estou canalizando comandos através de um shell, posso gerar comandos que obtêm o md5sum, como este
echo "1000-26092016" | md5sum
55b18a6b0add4a318b0079e18512b4e8 -
para obter apenas o hash
echo "1000-26092016" | md5sum | cut -d' ' -f 1
55b18a6b0add4a318b0079e18512b4e8
Em um shell unix, podemos usar operadores de backtick (`some_command`) para executar um subcomando, portanto, por exemplo
echo "howdy date there"
howdy date there
echo "howdy `date` there"
howdy Fri Sep 15 18:39:00 IST 2017 there
De volta ao comando mv, quero que o sed produza "mv here there" com "there" substituído por um comando backtick para obter o md5sum. A cadeia dentro da cadeia de substituição sed começa assim
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
Mas está claramente criando o mesmo hash para cada nome de arquivo, pois o comando backticked está sendo executado antes que o sed veja a string. Para impedir que o shell execute o comando backtick para que o sed produza os backticks, precisamos acrescentar barras (também ao caractere de pipe), então novamente:
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
A saída também precisa que os nomes dos arquivos sejam citados em caso de espaços, portanto
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"
Então, vamos experimentar este, canalizando-o através de um shell:
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick | sh -
Funcionou ? eu acho:
echo "a trick€€ fíle nÁme" | md5sum
629db9c3071928ba0746f18444713b65 -
ls 629db9c3071928ba0746f18444713b65*
629db9c3071928ba0746f18444713b65.xml
Aqui está uma abordagem para verificação cruzada; use a opção "ls" "-i" para gerar o nó i do sistema de arquivos unix (que não muda com "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"
Ou, usando o comando "colar" (pacote '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