Vous allez avoir quelques problèmes si vous voulez renommer des fichiers et des répertoires en même temps. Renommer juste un fichier est assez facile. Mais vous voulez vous assurer que les répertoires sont également renommés. Vous ne pouvez pas simplement, mv Motörhead/Encöding Motorhead/Encoding
car Motorhead
il n’existera pas au moment de l’appel.
Nous avons donc besoin d’une traversée d’abord en profondeur de tous les fichiers et dossiers, puis de renommer le fichier ou le dossier actuel uniquement. 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" ] # if equal, name is already clean, so leave alone
then
if [ -e "$d/$new" ]
then
echo "Notice: \"$new\" and \"$f\" both exist in "$d":"
ls -ld "$d/$new" "$d/$f"
else
echo mv "$file" "$d/$new" # remove "echo" to actually rename things
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 rename.sh
, rendez-le exécutable avec chmod +x rename.sh
. Ensuite, appelez ça comme rename.sh /some/path
.
Assurez-vous de résoudre les conflits de noms de fichiers ( Notice
annonces « »).
Si vous êtes absolument certain que le remplacement est correct, supprimez-le echo
du script pour renommer des éléments au lieu d’imprimer le résultat.
Pour plus de sécurité, je vous conseillerais de commencer par tester ceci sur un petit sous-ensemble de fichiers.
Options expliquées
Pour expliquer ce qui se passe ici:
-depth
veillera à ce que les répertoires soient récursifs en profondeur d'abord, afin que nous puissions "tout remonter" à partir de la fin. Habituellement, find
traverse différemment (mais pas en largeur d'abord).
-print0
assure que la find
sortie est délimitée par des valeurs nulles, afin que nous puissions la lire read -d ''
dans la file
variable. Cela nous aide à gérer toutes sortes de noms de fichiers étranges, y compris ceux avec des espaces et même des nouvelles lignes.
- Nous allons obtenir le répertoire du fichier avec
dirname
. N'oubliez pas de toujours citer correctement vos variables, sinon tout chemin contenant des espaces ou des caractères globaux briserait ce script.
- Nous allons obtenir le nom du fichier (ou nom du répertoire) avec
basename
.
- Ensuite, nous retirons tout caractère non valide de l'
$f
utilisation des capacités de remplacement de chaîne de Bash. Invalide signifie tout ce qui n'est pas une lettre minuscule ou majuscule, un chiffre, une barre oblique ( \/
), un point ( \.
), un trait de soulignement ou un tiret moins.
- Si
$f
est déjà propre (le nom nettoyé est identique au nom actuel), ignorez-le.
- S'il
$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, cela mv foo foo
pose un problème. Autrement,
- Nous avons finalement renommé le fichier (ou répertoire) d'origine en son nouveau nom.
Comme cela n'agit que sur la hiérarchie la plus profonde, le changement Motörhead/Encöding
de nom Motorhead/Encoding
se fait en deux étapes:
mv Motörhead/Encöding Motörhead/Encoding
mv Motörhead Motorhead
Cela garantit que tous les remplacements sont effectués dans le bon ordre.
Exemples de fichiers et test
Supposons quelques 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'une exécution en mode débogage (avec le echo
devant de 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
Notice: "resume" and "résumé" both exist in test/work:
-rw-r—r-- … … test/work/resume
-rw-r—r-- … … test/work/résumé
Notez l'absence de messages pour with-hyphen.txt
, schedule
et test
lui - même.
mv
existe déjà, ce qui peut arriver (1) si vous avez des fichiers déjà propres (résultantmv foo foo
), ou (2) si vous avez des fichiers du même nom sauf pour les caractères spéciaux (par exemple,mv Encöding Encoding
où vous avez déjà unEncoding
fichier en plus deEncöding
).