Script Bash[3] – renommer plusieurs fichiers – rename a bunch of files

Encore un pense-bête, cette fois pour faire du renommage massif de fichier, avec notamment sed et les expressions régulières.

Once again a reminder, today how-to mass-rename files, with sed and regular expressions.

Of course there is a lot of software[en] with graphical interface, user-friendly, etc. But hey, where is the fun !? ;)

As I have already shown you, simple script for simple renaming is sufficient:

for i in *.html; do mv $i.bak; done

You may also want to use find but I won’t go into details with it here.

You can use basename (and dirname) to do little more complicated:

for i in *htm; do mv $i `basename $i htm`html; done

or, some useful bash operator:

for i in *htm; do mv $i ${i%%.htm}.html; done

Little reminder:

With ## (resp. #) you can delete the longest (resp. shortest) substring corresponding to the pattern:

$ Name=’Rep/toto.tar.gz’
$ echo ${Name##*.}
> gz
$ echo ${Name#*.}
> tar.gz
$ echo ${Name##*t}
> ar.gz
$ echo ${Name#*t}
> oto.tar.gz

To do the same things with the end of the string use % (or %%):
$ echo ${Name%.*}
> Rep/toto.tar
$ echo ${Name%%.*}
> Rep/toto
$ echo ${Name%%t*}
> Rep/
$ echo ${Name%t*}
> Rep/toto.

More difficult, with Perl regular expressions and rename:

rename "s/htm/html/" *htm

Option -n to see what files would have been renamed.

Finally, with sed and regular expressions: You have files like 01_tilte1_album1.mp3, 03_tilte5_album9.mp3, and you want to delete the numbers; Or files like title_01_blabla.srt, title_02_blabla.srt and you want to remove all the title and blabla ? Here we go:

ls | sed -rn "s/^[0-9]+_(.*)/mv '&' '\1'/ p" | sh

-n : quiet mode
-r : extended regular expressions
^[0-9]+_ : start with some digits, followed by an underscore
(.*) : what we will keep
mv ‘&’ ‘\1’ : what we will do : move the matching files (‘&’) to what we will keep (‘\1’)
p : print the command
|sh : execute the command
Thus with only ls | …. p” you will see what files are concerned.

$ for i in `seq 8 1 12`; do touch $i\_title$i\_name$i\_$i$i.htm; done
$ ls
> 10_title10_name10_1010.htm 11_title11_name11_1111.htm 12_title12_name12_1212.htm 8_title8_name8_88.htm
> 9_title9_name9_99.htm
$ ls | sed -rn “s/^[0-9]+_(.*)htm/mv ‘&’ ‘\1’html/ p”
>
mv ’10_title10_name10_1010.htm’ ‘title10_name10_1010.’html
mv ’11_title11_name11_1111.htm’ ‘title11_name11_1111.’html
mv ’12_title12_name12_1212.htm’ ‘title12_name12_1212.’html
mv ‘8_title8_name8_88.htm’ ‘title8_name8_88.’html
mv ‘9_title9_name9_99.htm’ ‘title9_name9_99.’html
$ ls | sed -rn “s/.*(title.*)_name.*_(.*)htm/mv ‘&’ ‘\1_\2’html/ p”
>
mv ’10_title10_name10_1010.htm’ ‘title10_1010.’html
mv ’11_title11_name11_1111.htm’ ‘title11_1111.’html
mv ’12_title12_name12_1212.htm’ ‘title12_1212.’html
mv ‘8_title8_name8_88.htm’ ‘title8_88.’html
mv ‘9_title9_name9_99.htm’ ‘title9_99.’html
$ ls | sed -rn “s/^([0-9]+)_.*/mv ‘&’ ‘\1.html’/ p”
>
mv ’10_title10_name10_1010.htm’ ’10.html’
mv ’11_title11_name11_1111.htm’ ’11.html’
mv ’12_title12_name12_1212.htm’ ’12.html’
mv ‘8_title8_name8_88.htm’ ‘8.html’
mv ‘9_title9_name9_99.htm’ ‘9.html’

You just have to find the good regular expression, and then add the ‘| sh’ to execute ;)

And if you want to substitute underscores for blanks in all the filenames in a directory with a real script in your mybin directory:


#! /bin/bash
# blank-rename.sh
#
# Substitutes underscores for blanks in all the filenames in a directory.
ONE=1 # For getting singular/plural right (see below).
number=0 # Keeps track of how many files actually renamed.
FOUND=0 # Successful return value.

for filename in * #Traverse all files in directory.
do
echo “$filename” | grep -q ” ” # Check whether filename
if [ $? -eq $FOUND ] #+ contains space(s).
then
fname=$filename # Yes, this filename needs work.
n=`echo $fname | sed -e “s/ /_/g”` # Substitute underscore for blank.
mv “$fname” “$n” # Do the actual renaming.
let “number += 1”
fi
done

if [ “$number” -eq “$ONE” ] # For correct grammar.
then
echo “$number file renamed.”
else
echo “$number files renamed.”
fi
exit 0

Source : advanced bash script guide[en], ShQWiki[en], the teaching of Emmanuel Viennet[fr], some fora, …

And please, do backups

Évidemment, il y a tout un tas de programmes[en] avec des interfaces utilisateurs, c’est joli et tout mais, où est le plaisir !? ;)

Comme je vous l’ai déjà montré, un script tout bête suffit à un renommage tout bête :

for i in *.html; do mv $i.bak; done

On peut utiliser basename (and dirname) pour faire un peu plus dur :

for i in *htm; do mv $i `basename $i htm`html; done

ou utiliser un opérateur bash :

for i in *htm; do mv $i ${i%%.htm}.html; done

Petit rappel :

Avec ## (resp. #) on peut supprimer la plus longue (resp. courte) chaine correspondant au motif :

$ Nom=’Rep/toto.tar.gz’
$ echo ${Nom##*.}
> gz
$ echo ${Nom#*.}
> tar.gz
$ echo ${Nom##*t}
> ar.gz
$ echo ${Nom#*t}
> oto.tar.gz

Pour faire la même chose avec la fin de la chaine, utilisez % (ou %%) :
$ echo ${Nom%.*}
> Rep/toto.tar
$ echo ${Nom%%.*}
> Rep/toto
$ echo ${Nom%%t*}
> Rep/
$ echo ${Nom%t*}
> Rep/toto.

Plus difficile, avec les expressions régulières de Perl et rename:

rename "s/htm/html/" *htm

Option -n pour voir les fichiers qui devraient être renommés.

Finallement, avec sed et les expressions régulières : vous avez des fichiers de la forme 01_tilte1_album1.mp3, 03_tilte5_album9.mp3, et vous voulez enlever les nombres ? ou des fichiers comme title_01_blabla.srt, title_02_blabla.srt et vous voulez virerle titre et le blabla ? C’est parti :

ls | sed -rn "s/^[0-9]+_(.*)/mv '&' '\1'/ p" | sh

-n : mode silencieux
-r : expressions régulières étendues
^[0-9]+_ : commence par des chiffres, suivis par un tiret bas
(.*) : ce qu’on va garder
mv ‘&’ ‘\1’ : ce qu’on va faire : déplacer le fichier correspondant au motif (‘&’) vers ce que l’on veut garder (‘\1’)
p : affiche la commande
|sh : exécute la commande
Donc avec seulement ls | …. p” vous verrez les fichiers concernés

$ for i in `seq 8 1 12`; do touch $i\_title$i\_name$i\_$i$i.htm; done
$ ls
> 10_title10_name10_1010.htm 11_title11_name11_1111.htm 12_title12_name12_1212.htm 8_title8_name8_88.htm
> 9_title9_name9_99.htm
$ ls | sed -rn “s/^[0-9]+_(.*)htm/mv ‘&’ ‘\1’html/ p”
>
mv ’10_title10_name10_1010.htm’ ‘title10_name10_1010.’html
mv ’11_title11_name11_1111.htm’ ‘title11_name11_1111.’html
mv ’12_title12_name12_1212.htm’ ‘title12_name12_1212.’html
mv ‘8_title8_name8_88.htm’ ‘title8_name8_88.’html
mv ‘9_title9_name9_99.htm’ ‘title9_name9_99.’html
$ ls | sed -rn “s/.*(title.*)_name.*_(.*)htm/mv ‘&’ ‘\1_\2’html/ p”
>
mv ’10_title10_name10_1010.htm’ ‘title10_1010.’html
mv ’11_title11_name11_1111.htm’ ‘title11_1111.’html
mv ’12_title12_name12_1212.htm’ ‘title12_1212.’html
mv ‘8_title8_name8_88.htm’ ‘title8_88.’html
mv ‘9_title9_name9_99.htm’ ‘title9_99.’html
$ ls | sed -rn “s/^([0-9]+)_.*/mv ‘&’ ‘\1.html’/ p”
>
mv ’10_title10_name10_1010.htm’ ’10.html’
mv ’11_title11_name11_1111.htm’ ’11.html’
mv ’12_title12_name12_1212.htm’ ’12.html’
mv ‘8_title8_name8_88.htm’ ‘8.html’
mv ‘9_title9_name9_99.htm’ ‘9.html’

Vous avez juste à trouver les bonnes expressions régulières, et à ajouter le ‘| sh’ pour exécuter ;)

Et si vous voulez changer les blancs dans les noms de fichiers par des tirets bas avec un script que vous aurez mis dans votre dossier monbin:


#! /bin/bash
# blank-rename.sh
#
# Substitue les tirets soulignés par des blancs dans tous les fichiers d'un
# répertoire.
UN=1 # Pour obtenir le singulier/pluriel correctement (voir
# plus bas).
nombre=0 # Garde trace du nombre de fichiers renommés.
TROUVE=0 # Valeur de retour en cas de succès.

for fichier in * #Traverse tous les fichiers du répertoire.
do
echo “$fichier” | grep -q ” ” # Vérifie si le nom du fichier
if [ $? -eq $TROUVE ] #+ contient un (des) espace(s).
then
nomf=$fichier # Supprime le chemin.
n=`echo $nomf | sed -e “s/ /_/g”` # Remplace l’espace par un tiret.
mv “$nomf” “$n” # Réalise le renommage.
let “nombre += 1”
fi
done
if [ “$nombre” -eq “$UN” ] # Pour une bonne grammaire.
then
echo “$nombre fichier renommé.”
else
echo “$nombre fichiers renommés.”
fi

source : advanced bash script guide[fr], ShQWiki[en], le cours d’Emmanuel Viennet[fr], des fora, …

Et n’oubliez pas, faites des sauvegardes ;)

~ by loquehumaine on 2007, November 12 - Monday.

One Response to “Script Bash[3] – renommer plusieurs fichiers – rename a bunch of files”

  1. merci, la partie sur le renomage de fichiers en sed m’a permis de résoudre un problème correctement et rapidement :thumbsup:

Leave a comment