Comment renommer en bloc des fichiers avec un encodage non valide ou remplacer en bloc des caractères encodés non valides?

15

J'ai un serveur Debian et j'héberge 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 encodage 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-zou des chiffres 0-9ou des tirets -/ soulignés _... 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 fichiers et de répertoires?

J'ai vu cette question similaire: renommer en bloc (ou afficher correctement) des fichiers avec des caractères spéciaux

Mais cela ne corrige que l'encodage, je préférerais une approche plus stricte comme décrit ci-dessus.

Waqar Lim
la source

Réponses:

14

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/Encodingcar Motorheadil 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 findet 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 ( Noticeannonces « »).

Si vous êtes absolument certain que le remplacement est correct, supprimez-le echodu 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:

  • -depthveillera à ce que les répertoires soient récursifs en profondeur d'abord, afin que nous puissions "tout remonter" à partir de la fin. Habituellement, findtraverse différemment (mais pas en largeur d'abord).
  • -print0assure que la findsortie est délimitée par des valeurs nulles, afin que nous puissions la lire read -d ''dans la filevariable. 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' $futilisation 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 $fest déjà propre (le nom nettoyé est identique au nom actuel), ignorez-le.
  • S'il $newexiste déjà dans le répertoire $d(par exemple, vous avez des fichiers nommés resumeet 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 foopose 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ödingde nom Motorhead/Encodingse fait en deux étapes:

  1. mv Motörhead/Encöding Motörhead/Encoding
  2. 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 echodevant 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, scheduleet testlui - même.

slhck
la source
1
Vous voudrez peut-être ajouter une logique pour gérer le cas où la destination de la destination mvexiste déjà, ce qui peut arriver (1) si vous avez des fichiers déjà propres (résultant mv 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 Encodingoù vous avez déjà un Encodingfichier en plus de Encöding).
Scott le
Bonne idée, merci Des suggestions spécifiques sur ce qu'il faut faire dans ce cas? Certes, il est plus difficile d’atteindre cet objectif qu’il semble au premier abord. Si vous avez quelque chose, n'hésitez pas à éditer des cours.
Slhck
Je ne crois pas qu'il soit logique de penser à gérer les collisions automatiquement - il suffit de les identifier à l'utilisateur et de le laisser le gérer. J'ai modifié votre réponse, comme vous l'avez suggéré.
Scott
+1 pour utiliser l'exemple avec "Encöding" Too much fön! :-)
Marcel
Après trois ans, je reviens encore ici. tellement utile! :-)
Waqar Lim
15

Je sais que ce n'est pas exactement ce que vous vouliez, mais si vous connaissez le codage d'origine, vous pouvez peut-être utiliser convmvpour changer le codage en UTF-8, ce qui devrait résoudre la plupart des problèmes.

Cela a fonctionné pour moi sur un dossier avec certains noms de fichiers polonais encodés de manière invalide:

convmv -f cp1250 -t utf8 -r .

Notez que cette commande ne renomme réellement rien; ajouter une --notestoption pour vraiment renommer les fichiers.

mik01aj
la source
1
Pour ceux qui ont un ensemble statique (ou qui n'ont pas un mélange de caractères différent), l' convmvoption est incroyablement simple et parfaite. Pour OP, ayant une multitude de jeux de caractères potentiels, cela pourrait être fusionné avec l’autre réponse, car il convmvsemble savoir quand ou non il rencontre le bon format. En parcourant les jeux de caractères via convmv --list, on les obtiendrait correctement codés.
1
J'entends par là que si, en tant qu'OP, utilise un serveur Debian, on suppose certainement UTF8 ces jours-ci, auquel cas, on peut conserver les lettres originales. J'avais un dossier de caractères nordiques, et utilisé: convmv -t utf8 --nfc -f iso-8859-1 --notest -r .- --nfcC'était pour se conformer à Linux avant OS X ou autre, taper simplement convmvdonne les options (utiles).
0

Je sais, vous avez demandé à renommer.

Mais vous pouvez facilement éviter le problème en utilisant un logiciel comme MusicBrainz Picard .

Il est capable d'identifier la musique (empreintes audio), de télécharger toutes les données nécessaires (y compris les images de couverture, le cas échéant) à partir de la vaste base de données MusicBrainz et de déplacer les fichiers pour que votre collection s'adapte à tous les motifs de votre choix. Je l'utilise depuis des années et cela a toujours fonctionné parfaitement avec tout, de Cyrilic à l'Arabe; et bien sûr (du moins pour les scripts basés sur le latin), il peut également effectuer la conversion en ASCII.

Avec cette approche, peu importe la qualité de votre collection, tant que les fichiers sont lisibles et complets.

(Ai-je mentionné que c'était gratuit? Aussi bien dans la liberté d'expression que dans la bière gratuite? Le logiciel et la base de données ..?)

Alois Mahdal
la source