C'est une approche que j'aime souvent utiliser.
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \1.\2 \\`echo \1 \| md5sum \| cut -d' ' -f 1\\`.\2|" | sh -
La commande "ls" produit un flux de lignes de texte. La commande "sed" transforme chaque ligne avec des règles de correspondance de motifs. La commande "sed" génère une commande "mv" qui est ensuite envoyée via un shell "sh" pour exécution. Les paramètres de la commande "mv" sont comme "mv oldfilename newfilename", qui renomme le fichier. Je construis le nouveau nom de fichier avec une commande sed qui prend la partie avant le dernier point, et l'écho dans l'entrée de la commande "md5sum", puis prend juste le hachage de sa sortie.
En parcourant mon processus, commencez par lister les fichiers ('head -n 3' pour ne voir que les 3 premières lignes):
ls | head -n 3
1000-26092016.xml
1000-27092016.xml
12312-28092016.xml
Pensez ensuite à transformer avec sed (pas encore de piping de commandes générées via un 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
Il existe trois modèles de correspondance:
^\(.*\) = match from start-of-line up to a dot
\. = matches a single dot
\([^\.]*\)$ = match 0-or-more non-dot chars from end of line
Je veux utiliser sed pour remplacer un nom de fichier d'entrée par "mv filename NEWfilename", mais comme je passe des commandes via un shell, je peux générer des commandes qui obtiennent le md5sum, comme ceci
echo "1000-26092016" | md5sum
55b18a6b0add4a318b0079e18512b4e8 -
pour obtenir juste le hachage
echo "1000-26092016" | md5sum | cut -d' ' -f 1
55b18a6b0add4a318b0079e18512b4e8
Dans un shell Unix, nous pouvons utiliser des opérateurs de backtick (`some_command`) pour exécuter une sous-commande, donc par exemple
echo "howdy date there"
howdy date there
echo "howdy `date` there"
howdy Fri Sep 15 18:39:00 IST 2017 there
De retour à la commande mv, je veux que sed produise "mv here there" avec "there" remplacé par une commande backtick pour obtenir le md5sum. La chaîne à l'intérieur de la chaîne de remplacement sed commence comme ceci
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
Mais fait clairement le même hachage pour chaque nom de fichier, car la commande backticked est exécutée avant que sed ne voie la chaîne. Pour arrêter le shell exécutant la commande backtick afin que sed produise les backticks, nous devons ajouter des barres obliques (également au caractère pipe), encore une fois:
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
La sortie a également besoin que les noms de fichiers soient cités en cas d'espaces, donc
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"
Essayons donc celui-ci, en le passant à travers un shell:
ls | sed "s|^\(.*\)\.\([^\.]*\)$|mv \"\1.\2\" \"\`echo \1 \| md5sum \| cut -d' ' -f 1\`.\2\"|" | grep trick | sh -
Cela a-t-il fonctionné? j'imagine:
echo "a trick€€ fíle nÁme" | md5sum
629db9c3071928ba0746f18444713b65 -
ls 629db9c3071928ba0746f18444713b65*
629db9c3071928ba0746f18444713b65.xml
Voici une approche de recoupement; utilisez "ls" option "-i" pour sortir le i-node du système de fichiers unix (qui ne change pas avec "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, en utilisant la commande "coller" (package '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