web-dev-qa-db-fra.com

Utilisation de sed pour renommer en masse des fichiers

Objectif

Changer ces noms de fichiers:

  • F00001-0708-RG-partialliuyda
  • F00001-0708-CS-akgdlaul
  • F00001-0708-VF-hioulgigl

à ces noms de fichiers:

  • F0001-0708-RG-partialliuyda
  • F0001-0708-CS-akgdlaul
  • F0001-0708-VF-hioulgigl

Shell Code

Tester:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/'

Pour effectuer:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh

Ma question

Je ne comprends pas le code sed. Je comprends ce que la substitution Commande

$ sed 's/something/mv'

veux dire. Et je comprends un peu les expressions régulières. Mais je ne comprends pas ce qui se passe ici:

\(.\).\(.*\)

ou ici:

& \1\2/

Le premier, pour moi, ressemble à cela signifie: "un seul caractère, suivi par un seul caractère, suivi de toute séquence de longueur d'un caractère unique " - mais il y a sûrement plus que cela. En ce qui concerne La dernière partie:

& \1\2/

Je n'ai aucune idée. Je veux vraiment comprendre ce code. S'il vous plaît, aidez-moi, ici, les gars.

67
Daniel Underwood

Premièrement, je devrais dire que le moyen le plus simple de procéder consiste à utiliser les commandes Prename ou à renommer.

Sous Ubuntu, OSX (paquet Homebrew rename, paquet MacPorts p5-file-rename) ou d’autres systèmes avec renom Perl (prename):

rename s/0000/000/ F0000*

ou sur des systèmes renommés depuis util-linux-ng, tels que RHEL:

rename 0000 000 F0000*

C'est beaucoup plus compréhensible que la commande sed équivalente.

Mais pour ce qui est de comprendre la commande sed, la page de manuel sed est utile. Si Vous lancez man sed et recherchez & (en utilisant la commande/pour rechercher), Vous constaterez que c'est un caractère spécial dans s/foo/bar/replacements.

  s/regexp/replacement/
         Attempt  to match regexp against the pattern space.  If success‐
         ful,  replace  that  portion  matched  with  replacement.    The
         replacement may contain the special character & to refer to that
         portion of the pattern space  which  matched,  and  the  special
         escapes  \1  through  \9  to refer to the corresponding matching
         sub-expressions in the regexp.

Par conséquent, \(.\) correspond au premier caractère, qui peut être référencé par \1. Ensuite, . correspond au caractère suivant, qui est toujours 0 . Ensuite, \(.*\) correspond au reste du nom de fichier, qui peut être référencé par \2.

La chaîne de remplacement assemble le tout en utilisant & (le fichier Nomfichier d'origine) et \1\2, qui représente toutes les parties du nom de fichier, sauf le 2e caractère , Qui était un 0.

Ceci est une façon assez cryptique de le faire, à mon humble avis. Si, pour une raison quelconque, la commande renommer n’était pas disponible et que vous vouliez utiliser Sed pour renommer (ou peut-être que vous faisiez quelque chose de trop complexe Pour renommer?), Être plus explicite dans votre regex le rendre beaucoup plus lisible. Peut-être quelque chose comme:

ls F00001-0708-*|sed 's/F0000\(.*\)/mv & F000\1/' | sh

Etre capable de voir ce qui change réellement dans le fichier S/search/replacement/le rend beaucoup plus lisible. En outre, il ne gardera pas les caractères sucer hors de votre nom de fichier si vous le lancez accidentellement .__ deux fois ou quelque chose du genre.

125
Edward Anderson

vous avez eu votre explication sed, maintenant vous pouvez utiliser uniquement le shell 

for file in F0000*
do
    echo mv "$file" "${file/#F0000/F000}"
    # ${file/#F0000/F000} means replace the pattern that starts at beginning of string
done
36
ghostdog74

J'ai écrit un petit article avec des exemples sur le renommage par lots en utilisant sed il y a quelques années:

http://www.guyrutenberg.com/2009/01/12/batch-renaming-using-sed/

Par exemple:

for i in *; do
  mv "$i" "`echo $i | sed "s/regex/replace_text/"`";
done

Si l'expression régulière contient des groupes (par exemple \(subregex\), vous pouvez les utiliser dans le texte de remplacement en tant que \1\, \2 etc.

16
Guy

Le moyen le plus simple serait:

for i in F00001*; do mv "$i" "${i/F00001/F0001}"; done

ou, de manière portable,

for i in F00001*; do mv "$i" "F0001${i#F00001}"; done

Ceci remplace le préfixe F00001 dans les noms de fichiers par F0001. Crédits à mahesh ici: http://www.debian-administration.org/articles/150

14
Mike

La commande sed

s/\(.\).\(.*\)/mv & \1\2/

moyens de remplacer:

\(.\).\(.*\)

avec:

mv & \1\2

comme une commande sed normale. Cependant, les marqueurs entre parenthèses, & et \n le changent un peu.

La chaîne de recherche correspond (et mémorise en tant que motif 1) au caractère unique au début, suivi d'un seul caractère suivi du reste de la chaîne (mémorisée en tant que motif 2).

Dans la chaîne de remplacement, vous pouvez vous référer à ces modèles correspondants pour les utiliser dans le cadre du remplacement. Vous pouvez également vous référer à la partie correspondante sous la forme &.

Ainsi, la commande sed crée une commande mv basée sur le fichier d'origine (pour la source) et les caractères 1 et 3, en supprimant le caractère 2 (pour la destination). Il vous donnera une série de lignes selon le format suivant:

mv F00001-0708-RG-biasliuyda F0001-0708-RG-biasliuyda
mv abcdef acdef

etc.

6
paxdiablo

Le terme "backslash-paren" signifie "tout en respectant le motif, conservez le contenu correspondant". Plus tard, du côté du texte de remplacement, vous pouvez récupérer ces fragments avec "\ 1" (premier bloc entre parenthèses), "\ 2" (deuxième bloc), etc.

2
Pointy

Voici ce que je ferais:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done

Si cela vous convient, ajoutez | sh à la fin. Alors:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done | sh
0
Chris Po

Les parenthèses capturent des chaînes particulières à utiliser par les nombres inversés.

0
Ewan Todd
 ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash
0
ghostdog74

Si tout ce que vous faites, c'est supprimer le deuxième caractère, peu importe sa nature, vous pouvez le faire:

s/.//2

mais votre commande est en train de construire une commande mv et de la diriger vers le shell pour exécution.

Ce n'est pas plus lisible que votre version:

find -type f | sed -n 'h;s/.//4;x;s/^/mv /;G;s/\n/ /g;p' | sh

Le quatrième caractère est supprimé car find ajoute chaque nom de fichier avec "./".

0