Rename et $

Bonjour à tous,

Je suis entrain d’écrire un petit script très simple pour automatiser des conversions de fichiers musicaux en mp3 avec ffmpeg. C’est un script interactif qui exécute des commandes selon les réponses que je lui apporte. Il est structuré en trois étapes, Conversion des fichiers, renommage des fichiers pour en faire disparaître l’ancienne extension (ex : $file.m4a.mp3 -----> $file.mp3), puis supprimer les fichiers d’origine (autre que mp3).

Voici comment se déroule l’étape de “renommage” :

echo -e "Extension à supprimer ?" read extension rename 's/\.$extension.mp3$/\.mp3/' *.$extension.mp3

Cette dernière ligne ne fonctionne pas, même en dehors du script par utilisation en shell simple. Il semble que l’utilisation de la fonction $ ne soit pas compatible, voici le message d’erreur qui m’est retourné : Global symbol “$extension” requires explicit package name at (user-supplied code). En regardant sur internet, je trouve bien de la doc, mais ça concerne surtout du perl…

Quelqu’un saurait-il rendre cette commande fonctionnelle ?

Si besoin est voici le script complet. Je vous demande votre indulgence ceci est d’un niveau débutant.

echo -e "\E[36;40mLes fichiers à  convertir sont :" 
echo -e $1
echo -e $2
echo -e $3
echo -e $4
echo -e $5
echo -e $6
echo -e $7
echo -e $8
echo -e $9
echo -e ${10}
echo -e ${11}
echo -e ${12}
echo -e ${13}
echo -e ${14}
echo -e ${15}
echo -e "Voulez-vous lancer la conversion ?"
read choix
case $choix in
[OoYy]*) ffmpeg -i "$1" "$1.mp3"
         ffmpeg -i "$2" "$2.mp3"
         ffmpeg -i "$3" "$3.mp3"
         ffmpeg -i "$4" "$4.mp3"
         ffmpeg -i "$5" "$5.mp3"
         ffmpeg -i "$6" "$6.mp3"
         ffmpeg -i "$7" "$7.mp3"
         ffmpeg -i "$8" "$8.mp3"
         ffmpeg -i "$9" "$9.mp3"
         ffmpeg -i "${10}" "${10}.mp3"
         ffmpeg -i "${11}" "${11}.mp3"
         ffmpeg -i "${12}" "${12}.mp3"
         ffmpeg -i "${13}" "${13}.mp3"
         ffmpeg -i "${14}" "${14}.mp3"
         ffmpeg -i "${15}" "${15}.mp3"
         echo -e "Conversion terminées"
         echo -e "Corriger les noms des fichiers ? (suppression ancienne extension)";; 
[Nn]*) exit 0;;
esac
read reponse
case $reponse in
[OoYy]*) echo -e "Extension à  supprimer ?"
         read extension 
         rename 's/\.$extension.mp3$/\.mp3/' *.$extension.mp3 
         echo -e "Supprimer les anciens fichiers ?";;
[Nn]*) echo -e "Les fichiers n'ont pas été renommé"
       exit 0;;
esac
read volonte
case $volonte in
[OoYy]*) rm *.$extension
         echo -e "Fichiers supprimé"
         exit 0;;
[Nn]*) exit 0;;
esac

Merci.

Salut,
pour rename, je pense que ton problème est qu’avec des guillemets simples, ‘$extension’ n’est pas remplacé (ce qui est un comportement normal). Pour régler ça, soit tu utilises des guillemets doubles et tu fais attention d’échapper les caractères qu’il faut ($ et \ je pense), soit tu utilises la concaténation qui se fait toute seule avec :'s/\.'$extension'.mp3$/\.mp3/'

Sinon, les 15 lignes pour echo $i, ça se remplace facilement par un boucle sur $@ du style de :

for file in $@
    do echo $file
done

et pareil pour le reste.
Ça te permettra en prime de pouvoir accepter un nombre quelconque d’arguments.

Enfin, tu peux regarder select qui me semble adapté dans ton cas (un peu de doc : http://blaireaulinux.free.fr/linux-scripts-bash-7.php on doit pouvoir trouver d’autres sources, j’ai cherché 30 secondes :))

Merci de la réponse. La concaténation de la valeur $extension rend la commande fonctionnelle, c’est parfait.

Pour les multiples lignes $1, $2, $3, …, $n, effectivement je souhaiterai vraiment les remplacer par une seule ligne rendant tout nombre d’argument possible. J’ai essayé avec $@ mais, elle pose problème : $@ attribue un argument à chaque mot et non à chaque fichier. J’explique par un exemple :

Dans le dossier chanson, on a :
01 Chanson du samedi soir.wav
02 Chanson du mercredi à 14h.wav
03 Chanson…

Une structure de ce genre rend ceci lors du echo :
01
Chanson
du
samedi
soir.wav
02
Chanson
du
mercredi
à
14h.wav
etc…

Et du coup ca rend inopérante les conversions, basées sur la même idée puisque ffmpeg me renvoie qu’il ne trouve pas les fichiers 01, Chanson, du, etc…

Bon en tout cas, sans ça, le script fonctionne, et il me reste plus qu’à corriger ce bricolage de lignes multiples. J’imagine qu’il faut juste rajouter une spécification aux commandes que tu me proposes, la solution ne doit pas être loin.

Merci pour la doc, je vais regarder ça. J’y trouverai sans doute la solution à ce problème de $@.

for file in "${@}"
    do echo "${file}"
done
1 J'aime

Eh, oui, @MicP a absolument raison … cela fait partie des bonnes recommandations shell, une variable doit absolument être échappée correctement … telle que “${var}” … cela permet assurément de s’assurer de la valeur contenue de ladite variable et c’est encore plus criant quand ladite variable est un tableau … si elle n’est pas échappée correctement, le résultat attendu est peu ou prou le résultat retourné par le shell.

Donc, écris, et échappe correctement tes … “${var}”, quand tu veux les utiliser ailleurs …

Effectivement, dans certains cas, les guillemets ne sont pas une option, et donc ma proposition ne pouvait pas marcher…

Par contre, les accolades ne servent pas dans ce cas à ma connaissance, et ne sont utiles pour moi que si la variable est immédiatement suivie par un truc qui pourrait faire partie du nom de la variable (je laisse de côté les substitutions, parce que c’est évident que pour ${var//\#}, on a besoin d’accolades…).
Donc en résumé, pour ${var}iable, oui, il faut les accolades car c’est pas pareil que $variable, mais quand on n’a une chaîne qui ne contient qu’une variable, ça ne sert à rien et ça alourdit la commande, je trouve…

En bref, la solution de MicP est strictement équivalente à :

for file in "$@"
    do echo "$file"
done

voire à :

for file
    do echo "$file "
done

(je viens de découvrir que si on omettait « in …», par défaut ça faisait « in “$@” », mais je pense que c’est mieux d’éviter si un jour quelqu’un doit relire le script (son auteur compris) :slight_smile: )

Bien sûr, si tes noms de fichiers contiennent des espaces, il faut soit les échapper avec un backslash, soit mettre des guillemets autour de chaque nom.

Merci à vous. La nomenclature de @MicP fonctionne à merveille et avec la solution de David_5.1 pour rename tout est résolu. J’essaierai dans les prochains jours, à titre de curiosité, les équivalences que tu me proposes David_5.1, afin d’en apprécier les résultats et du coup peut-être simplifier un peu mon petit script, mais ce pourquoi j’ai posté ici est fait. Tout fonctionne.

Mon script est très simple, d’un niveau débutant, et pour l’instant il me suffit très bien pour automatiser les conversions avec ffmpeg. Je le poste ici au cas ou un curieux viendrait à passer.

Merci à tous.

echo -e "\E[6;1mLes fichiers à convertir sont :\E[6;0m" 
for file in "${@}"
do echo -e "${file}"
done
echo -e "\E[6;1mVoulez-vous lancer la conversion ?\E[6;0m"
read choix
case $choix in
[OoYy]*) echo -e "\E[6;1mVers quel format ?\E[6;0m"
         read nextension
         for file in "${@}"
         do ffmpeg -i "${file}" "${file}.${nextension}"
         done
         echo -e "\E[6;1mConversion terminées\E[6;0m"
         echo -e "\E[6;1mSuppression de l'ancienne extension dans les titres.\nQuelle est-elle ?\E[6;0m";; 
[Nn]*) echo -e "\E[6;1mVoulez-vous renommer les fichiers ?\E[6;0m"
       read volonte
       case $volonte in
       [OoYy]*) echo -e "\E[6;1mQuelle est l'ancienne extension ?\E[6;0m" 
                read aextension
                echo -e "\E[6;1mQuelle est la nouvelle extension ?\E[6;0m"
                read nextension
                rename 's/\.'$aextension'.'$nextension'$/\.'$nextension'/' *.$aextension.$nextension
                echo -e "\E[6;1mFichiers renommé\E[6;0m" 
                echo -e "\E[6;1mSupprimer les anciens fichiers ?\E[6;0m"
                read supr
                case $supr in
                [OoYy]*) rm *.$aextension
                         echo -e "\E[6;1mFichiers supprimé\nFin du programme\E[6;0m"
                         exit 0;;
                [Nn]*) echo -e "\E[6;1mFin du programme\E[6;0m"
                       exit 0;;
                esac;;
       [Nn]*) echo -e "\E[6;1mFin du programme\E[6;0m"
              exit 0;;
       esac;;
esac
read aextension
rename 's/\.'$aextension'.'$nextension'$/\.'$nextension'/' *.$aextension.$nextension
echo -e "\E[6;1mSupprimer les anciens fichiers ?\E[6;0m"
read volonte
case $volonte in
[OoYy]*) rm *.$aextension
         echo -e "\E[6;1mFichiers supprimé\nFin du programme\E[6;0m"
         exit 0;;
[Nn]*) echo -e "\E[6;1mFin du programme\E[6;0m"
       exit 0;;
esac

Un truc que tu peux faire pour rendre ton script plus lisible facilement, c’est une fonction pour afficher du texte en gras du style de :

echo_bold (){
    echo -e "\E[6;1m${1}\E[6;0m"
}

et pour l’utiliser :

echo_bold "texte en gras"

PS : c’est pénible que le forum ne garde pas l’indentation… (édité suite à la réponse de seb-ksl)

Tu peux éviter ça en encadrant ton code de trois “backticks” : `.

Ex :

```
echo_bold (){
    echo -e "\E[6;1m${1}\E[6;0m"
}
```

donnera :

echo_bold (){
    echo -e "\E[6;1m${1}\E[6;0m"
}
2 J'aime

Merci :slight_smile: surtout que ça active en plus la coloration syntaxique.

J’avais essayé de bricoler avec des espaces insécables, dans l’aperçu ça marche, mais quand on poste, ils n’apparaissent plus…

@Briceco, n’hésite pas a éditer tes posts pour utiliser ça aussi :slight_smile:

Done. Oui c’est pratique.

1 J'aime