J'ai un serveur Debian et j'hôte de la musique pour une station de radio Internet. J'ai des problèmes avec les noms de fichiers et les chemins car beaucoup de fichiers ont un codage invalide, par exemple:
./music/Bändname - Some Title - additional Info/B�ndname - 07 - This Title Is Cörtain, The EncÃDing Not.mp3
Idéalement, je voudrais supprimer tout ce qui n'est pas des lettres A-Z
/a-z
ou chiffres 0-9
ou Dash -
/souligner _
... Le résultat devrait ressembler à quelque chose comme ça:
./music/Bndname-SomeTitle-additionalInfo/Bndname-07-ThisTitleIsCrtain,TheEncdingNot.mp3
Comment y parvenir pour un lot de nombreux fichiers et répertoires?
J'ai vu cette question similaire: Renommée en vrac (ou afficheur correctement) avec des caractères spéciaux
Mais cela ne résout que le codage, je préférerais une approche plus stricte comme décrit ci-dessus.
Vous allez courir dans certains problèmes si vous souhaitez renommer des 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'existe pas au moment de l'appel.
Ainsi, nous avons besoin d'une traversée de profondeur de tous les fichiers et dossiers, puis renommez uniquement le fichier ou le dossier actuel. Le suivant fonctionne avec GNU find
et bash 4.2.42 sur mon système d'exploitation 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 voulez remplacer tout ce que Windows ne peut pas gérer.
Sauvegardez ce script comme rename.sh
, le rendre exécutable avec chmod +x rename.sh
. Ensuite, appelez-le comme rename.sh /some/path
.
Assurez-vous de résoudre les collisions de noms de fichiers ("Notice
" annonces).
Si vous êtes absolument sûr Il fait le bon remplacement, supprimez le echo
du script pour renommer des choses au lieu de simplement imprimer ce qu'elle fait.
Pour être en sécurité, je recommanderais de tester cela sur un petit sous-ensemble de fichiers en premier.
Expliquer ce qui se passe ici:
-depth
S'assurera que les répertoires sont en premier de la profondeur, afin que nous puissions "rouler" tout de la fin. Habituellement, find
traverse différemment (mais pas de largeur - premier).-print0
assure que la sortie find
est délimitée, afin que nous puissions la lire avec read -d ''
dans la variable file
. Cela nous aide à faire face à toutes sortes de noms de fichiers étranges, y compris ceux avec des espaces et même de nouvelles lignes.dirname
. N'oubliez pas de toujours citer vos variables correctement, sinon un chemin avec des espaces ou des caractères de globe briserait ce script.basename
.$f
Utilisation des capacités de remplacement de chaîne de Bash. Invalide signifie tout ce qui n'est pas une lettre inférieure ou majuscule, un chiffre, une barre oblique (\/
), un point (\.
), un soulignement ou un trimphène moins.$f
est déjà propre (le nom nettoyé est identique au nom actuel), sautez-le.$new
existe déjà dans l'annuaire $d
(E.G., vous avez des fichiers nommés resume
et résumé
Dans le même répertoire), émettez un avertissement. Vous ne voulez pas renommer cela, car, sur certains systèmes, mv foo foo
provoque un problème. Sinon,Comme cela n'agira que sur la hiérarchie la plus profonde, renommer Motörhead/EncöDing
à Motorhead/Encoding
est fait en deux étapes:
mv Motörhead/EncöDing Motörhead/Encoding
mv Motörhead Motorhead
Cela garantit que tous les remplaçants sont effectués dans le bon ordre.
Supposons certains 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 mode de débogage (avec le echo
devant le mv
), c'est-à-dire que 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.
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 modifier le codage en UTF-8, qui devrait résoudre la plupart des problèmes.
Cela a fonctionné pour moi sur un dossier avec des noms de fichiers polonais codés non valides:
convmv -f cp1250 -t utf8 -r .
Notez que cette commande ne renommera rien; ajouter --notest
Option pour renommer réellement les fichiers.