Vous allez rencontrer des problèmes si vous voulez renommer des fichiers et des répertoires en même temps. Renommer simplement un fichier est assez facile. Mais vous devez vous assurer que les répertoires sont également renommés. Vous ne pouvez pas simplement mv Motörhead/Encöding Motorhead/Encoding
car Motorhead
n'existera pas au moment de l'appel.
Donc, nous avons besoin d'une traversée en profondeur de tous les fichiers et dossiers, puis de renommer uniquement le fichier ou le dossier actuel. Ce qui suit fonctionne avec GNU find
et Bash 4.2.42 sur mon OS X.
#!/usr/bin/env bash
find "$1" -depth -print0 | while IFS= read -r -d '' file; do
d="$( dirname "$file" )"
f="$( basename "$file" )"
new="${f//[^a-zA-Z0-9\/\._\-]/}"
if [ "$f" != "$new" ] # si égaux, le nom est déjà propre, donc laissez-le tel quel
then
if [ -e "$d/$new" ]
then
echo "Avis : \"$new\" et \"$f\" existent tous deux dans "$d":
ls -ld "$d/$new" "$d/$f"
else
echo mv "$file" "$d/$new" # supprimez "echo" pour effectivement renommer les choses
fi
fi
done
Vous pouvez changer l'expression régulière en utilisant new="${f//[\\\/\:\*\?\"<>|]/}"
si vous voulez remplacer tout ce que Windows ne peut pas gérer.
Enregistrez ce script sous le nom de rename.sh
, rendez-le exécutable avec chmod +x rename.sh
. Ensuite, appelez-le comme rename.sh /some/path
.
Assurez-vous de résoudre tout collision de noms de fichiers (annonces de "Avis
").
Si vous êtes absolument sûr qu'il effectue les bonnes substitutions, retirez le echo
du script pour effectivement renommer les choses au lieu de simplement afficher ce qu'il fait.
Pour être sûr, je recommanderais de tester cela d'abord sur un petit sous-ensemble de fichiers.
Explication des options
Pour expliquer ce qui se passe ici :
-depth
s'assurera que les répertoires sont parcourus en profondeur, de sorte que nous puissions "rembobiner" tout depuis la fin. Habituellement, find
parcourt différemment (mais pas en largeur d'abord).
-print0
garantit que la sortie de find
est délimitée par des zéros, afin que nous puissions la lire avec read -d ''
dans la variable file
. Cela nous aide à gérer toutes sortes de noms de fichiers bizarres, y compris ceux avec des espaces et même des sauts de ligne.
- Nous obtiendrons le répertoire du fichier avec
dirname
. N'oubliez pas de toujours bien mettre entre guillemets vos variables, sinon tout chemin avec des espaces ou des caractères génériques casserait ce script.
- Nous obtiendrons le nom de fichier réel (ou le nom de répertoire) avec
basename
.
- Ensuite, nous supprimons tout caractère invalide de
$f
en utilisant les capacités de remplacement de chaîne de Bash. Invalide signifie tout ce qui n'est pas une lettre majuscule ou minuscule, un chiffre, une barre oblique (\/
), un point (\.
), un trait de soulignement ou un tiret.
- Si
$f
est déjà propre (le nom nettoyé est identique au nom actuel), passez à côté.
- Si
$new
existe déjà dans le répertoire $d
(par exemple, vous avez des fichiers nommés resume
et résumé
dans le même répertoire), émettez un avertissement. Vous ne voulez pas le renommer, car, sur certains systèmes, mv foo foo
pose problème. Sinon,
- Nous renommons enfin le fichier (ou le répertoire) original avec son nouveau nom.
Étant donné que cela n'agira que sur la hiérarchie la plus profonde, renommer Motörhead/Encöding
en Motorhead/Encoding
se fait en deux étapes :
mv Motörhead/Encöding Motörhead/Encoding
mv Motörhead Motorhead
Cela garantit que toutes les substitutions sont faites dans le bon ordre.
Fichiers d'exemple et exécution de test
Supposons qu'il y ait des fichiers dans un dossier de base appelé test
:
test
test/Motörhead
test/Motörhead/anöther_file.mp3
test/Motörhead/Encöding
test/Randöm
test/Täst
test/Täst/Töst
test/with space
test/with-hyphen.txt
test/work
test/work/resume
test/work/résumé
test/work/schedule
Voici la sortie d'un exécution en mode débogage (avec le echo
devant le mv
), c'est-à-dire les commandes qui seraient appelées et les avertissements de collision :
mv test/Motörhead/anöther_file.mp3 test/Motörhead/another_file.mp3
mv test/Motörhead/Encöding test/Motörhead/Encoding
mv test/Motörhead test/Motorhead
mv test/Randöm test/Random
mv test/Täst/Töst test/Täst/Tost
mv test/Täst test/Tast
mv test/with space test/withspace
Avis : "resume" et "résumé" existent tous deux dans test/work :
-rw-r—r-- ... ... test/work/resume
-rw-r—r-- ... ... test/work/résumé
Remarquez l'absence de messages pour with-hyphen.txt
, schedule
, et test
lui-même.