Je sais que ce n'est pas exactement ce que vous vouliez, mais si vous connaissez l'encodage d'origine, vous pouvez peut-être utiliser convmv
pour changer l'encodage en UTF-8, ce qui devrait résoudre la plupart des problèmes.
Cela a fonctionné pour moi sur un dossier contenant des noms de fichiers polonais non valides :
convmv -f cp1250 -t utf8 -r .
Notez que cette commande ne renomme en fait rien; ajouter --notest
option pour vraiment renommer les fichiers.
Vous allez rencontrer des problèmes si vous souhaitez renommer les fichiers et 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
depuis Motorhead
n'existera pas au moment de l'appel.
Nous avons donc besoin d'un parcours 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" ] # 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 la regex en utilisant new="${f//[\\\/\:\*\?\"<>|]/}"
si vous souhaitez 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-le comme rename.sh /some/path
.
Assurez-vous de résoudre toutes les collisions de noms de fichiers ("Notice
" annonces).
Si vous êtes absolument sûr il fait les bons remplacements, supprimez le echo
du script pour renommer les choses au lieu de simplement imprimer ce qu'il fait.
Pour plus de sécurité, je vous recommande de tester d'abord ceci sur un petit sous-ensemble de fichiers.
Options expliquées
Pour expliquer ce qui se passe ici :
-depth
garantira que les répertoires sont récursifs en profondeur d'abord, afin que nous puissions tout "rouler" à partir de la fin. Habituellement,find
traverse différemment (mais pas en largeur d'abord).-print0
assure lefind
la sortie est délimitée par null, nous pouvons donc la lire avecread -d ''
dans lefile
variable. Cela nous aide à gérer toutes sortes de noms de fichiers étranges, y compris ceux avec des espaces et même des retours à la ligne.- Nous obtiendrons le répertoire du fichier avec
dirname
. N'oubliez pas de toujours mettre vos variables entre guillemets correctement, sinon tout chemin avec des espaces ou des caractères globaux casserait ce script. - Nous obtiendrons le nom de fichier réel (ou 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 minuscule ou majuscule, un chiffre, une barre oblique (\/
), un point (\.
), un trait de soulignement ou un trait d'union moins. - Si
$f
est déjà propre (le nom nettoyé est identique au nom actuel), ignorez-le. - Si
$new
existe déjà dans le répertoire$d
(par exemple, vous avez des fichiers nommésresume
etrésumé
dans le même répertoire), émettre un avertissement. Vous ne voulez pas le renommer, car, sur certains systèmes,mv foo foo
cause un problème. Sinon, - Nous renommons enfin le fichier (ou le répertoire) d'origine avec son nouveau nom
Comme cela n'agira que sur la hiérarchie la plus profonde, renommer Motörhead/Encöding
à 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 d'exécution
Supposons que certains fichiers se trouvent 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 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
Notice: "resume" and "résumé" both exist in 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.