web-dev-qa-db-fra.com

Comment bulk-renommer des fichiers avec codage incorrect ou en vrac-remplacez des caractères codés non valides?

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.

16
Afr

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.


Options expliquées

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.
  • Nous obtiendrons le répertoire du fichier avec 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.
  • Nous obtiendrons le nom de fichier (ou le nom du répertoire) avec basename.
  • Ensuite, nous supprimons tout caractère non valide de $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.
  • Si $f est déjà propre (le nom nettoyé est identique au nom actuel), sautez-le.
  • Si $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,
  • Nous renommerons enfin le fichier original (ou le répertoire) à son nouveau nom.

Comme cela n'agira que sur la hiérarchie la plus profonde, renommer Motörhead/EncöDing à Motorhead/Encoding est fait en deux étapes:

  1. mv Motörhead/EncöDing Motörhead/Encoding
  2. mv Motörhead Motorhead

Cela garantit que tous les remplaçants sont effectués dans le bon ordre.


Exemple de fichiers et de tests

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.

14
slhck

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.

15
mik01aj