¿Cómo cambiar el nombre de archivos con codificación no válida o reemplazar caracteres codificados no válidos?

15

Tengo un servidor Debian y estoy alojando música para una estación de radio por Internet. Tengo problemas con los nombres y las rutas de los archivos porque muchos archivos tienen una codificación no válida, por ejemplo:

./music/Bändname - Some Title - additional Info/B�ndname - 07 - This Title Is Cörtain, The EncÃding Not.mp3

Idealmente, me gustaría eliminar todo lo que no sean letras A-Z/ a-zo números 0-9o guiones -/ guiones bajos _... El resultado debería verse así:

./music/Bndname-SomeTitle-additionalInfo/Bndname-07-ThisTitleIsCrtain,TheEncdingNot.mp3

¿Cómo lograr esto para un lote de muchos archivos y directorios?

He visto esta pregunta similar: cambiar el nombre masivo (o mostrar correctamente) archivos con caracteres especiales

Pero esto solo corrige la codificación, preferiría un enfoque más estricto como se describe anteriormente.

Afr
fuente

Respuestas:

14

Usted va a ejecutar en algunos problemas si desea cambiar el nombre de archivos y directorios al mismo tiempo. Renombrar solo un archivo es bastante fácil. Pero desea asegurarse de que los directorios también cambien de nombre. No puede simplemente mv Motörhead/Encöding Motorhead/Encodingya Motorheadque no existirá en el momento de la llamada.

Por lo tanto, necesitamos un recorrido profundo de todos los archivos y carpetas, y luego cambiar el nombre del archivo o carpeta actual solamente. Lo siguiente funciona con GNU findy Bash 4.2.42 en mi 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

Puede cambiar la expresión regular utilizando new="${f//[\\\/\:\*\?\"<>|]/}"si desea reemplazar algo que Windows no puede manejar.

Guarde este script como rename.sh, hágalo ejecutable con chmod +x rename.sh. Entonces, llámalo como rename.sh /some/path.

Asegúrese de resolver cualquier colisión de nombre de archivo (" Notice" anuncios).

Si está absolutamente seguro de que realiza los reemplazos correctos, elimine echoel script para cambiar el nombre de las cosas en lugar de simplemente imprimir lo que hace.

Para estar seguro, recomendaría probar esto en un pequeño subconjunto de archivos primero.


Opciones explicadas

Para explicar lo que sucede aquí:

  • -depthasegurará que los directorios se recreen primero en profundidad, para que podamos "enrollar" todo desde el final. Por lo general, findatraviesa de manera diferente (pero no primero).
  • -print0garantiza que la findsalida esté delimitada por nulos, de modo que podamos leerla read -d ''en la filevariable. Hacerlo nos ayuda a lidiar con todo tipo de nombres de archivos extraños, incluidos los que tienen espacios e incluso nuevas líneas.
  • Obtendremos el directorio del archivo con dirname. No olvides citar siempre tus variables correctamente, de lo contrario, cualquier ruta con espacios o caracteres globales rompería este script.
  • Obtendremos el nombre de archivo real (o el nombre del directorio) con basename.
  • Luego, eliminamos cualquier carácter no válido del $fuso de las capacidades de reemplazo de cadenas de Bash. Inválido significa cualquier cosa que no sea una letra mayúscula o minúscula, un dígito, una barra diagonal ( \/), un punto ( \.), un guión bajo o un guión negativo.
  • Si $fya está limpio (el nombre limpio es idéntico al nombre actual), omítalo.
  • Si $newya existe en el directorio $d(por ejemplo, tiene archivos nombrados resumey résuméen el mismo directorio), emita una advertencia. No desea cambiarle el nombre porque, en algunos sistemas, mv foo foocausa un problema. De otra manera,
  • Finalmente cambiamos el nombre del archivo original (o directorio) a su nuevo nombre

Como esto solo actuará en la jerarquía más profunda, el cambio Motörhead/Encödingde nombre Motorhead/Encodingse realiza en dos pasos:

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

Esto garantiza que todos los reemplazos se realicen en el orden correcto.


Archivos de ejemplo y prueba de funcionamiento

Asumamos algunos archivos en una carpeta base llamada 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

Aquí está el resultado de una ejecución en modo de depuración (con el echofrente de la mv), es decir, los comandos que se llamarían y las advertencias de colisión:

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é

Nótese la ausencia de mensajes para with-hyphen.txt, scheduley testen sí.

slhck
fuente
1
Es posible que desee agregar lógica para manejar el caso en el que mvya existe el destino , lo que puede suceder (1) si tiene archivos que ya están limpios (lo que resulta en mv foo foo), o (2) si tiene archivos con el mismo nombre excepto para los caracteres especiales (por ejemplo, mv Encöding Encodingdonde ya tiene un Encodingarchivo además de Encöding).
Scott
Buena idea, gracias. ¿Alguna sugerencia específica sobre qué hacer en ese caso? Por supuesto, lograr esto de una manera limpia y sensata es más difícil de lo que parece al principio. Si tienes algo, no dudes en editarlo, por supuesto.
slhck
No creo que tenga sentido pensar en manejar las colisiones automáticamente, simplemente identificarlas para el usuario y dejar que las maneje. He editado su respuesta, como sugirió.
Scott
+1 por usar el ejemplo con "Encöding" Demasiado fön! :-)
Marcel
Después de tres años todavía regreso aquí. tan útil! :-)
Afr
15

Sé que no es exactamente lo que querías, pero si conoces la codificación original, quizás puedas usarla convmvpara cambiar la codificación a UTF-8, lo que debería solucionar la mayoría de los problemas.

Esto funcionó para mí en una carpeta con algunos nombres de archivo polacos codificados no válidos:

convmv -f cp1250 -t utf8 -r .

Tenga en cuenta que este comando en realidad no cambia el nombre de nada; Añadir --notestopción para realmente cambiar el nombre de los archivos.

mik01aj
fuente
1
Para aquellos que tienen un conjunto estático (o no tienen una combinación diversa de charsets), la convmvopción es increíblemente simple y perfecta. Para OP, que tiene una multitud potencial de conjuntos de caracteres, esto podría combinarse con la otra respuesta, ya que convmvparece saber cuándo o cuándo no encuentra el formato correcto. Al recorrer los charsets, vía convmv --list, uno los codificaría correctamente.
1
Con esto quiero decir, si, como OP, ejecuta un servidor Debian, uno ciertamente asumiría UTF8 en estos días, en cuyo caso, uno puede conservar las letras originales. Tenía una carpeta de algunos caracteres nórdicos, y usé: convmv -t utf8 --nfc -f iso-8859-1 --notest -r .- --nfcDebía conformarme con Linux antes que OS X más o menos, simplemente escribir convmvda las opciones (útiles).
0

Lo sé, preguntaste por renombrar.

Pero puede esquivar el problema con bastante facilidad utilizando software como MusicBrainz Picard .

Es capaz de identificar música (huellas digitales de audio), descargar todos los datos necesarios (incluidas las imágenes de portada, donde estén disponibles) de la enorme base de datos MusicBrainz y mover los archivos para que su colección se ajuste a cualquier patrón que desee. Lo uso durante años y siempre funcionó perfectamente con cualquier cosa, desde cirílico hasta árabe; y por supuesto (al menos para los scripts basados ​​en latín) también puede hacer la conversión a ASCII.

Con este enfoque, realmente no importa cuán desordenado / mal nombrado esté realmente su colección, siempre que los archivos sean legibles y completos.

(¿Mencioné que es gratis? ¿Tanto en la libertad de expresión como en la cerveza gratis? ¿Tanto el software como la base de datos ...?)

Alois Mahdal
fuente