¿Cómo eliminar caracteres no válidos de los nombres de archivo?

47

Tengo archivos con caracteres no válidos como estos

009_-_�%86ndringshåndtering.html

Es un lugar Ædonde algo salió mal en el nombre del archivo.

¿Hay alguna manera de eliminar todos los caracteres no válidos?

o podría trser usado de alguna manera?

echo "009_-_�%86ndringshåndtering.html" | tr ???
Sandra
fuente
55
Los caracteres probablemente no son "inválidos", de lo contrario, el sistema de archivos no los almacenaría (a menos que haya hecho algo realmente desagradable para el FS). ¿Ha intentado cambiar su configuración regional (por ejemplo, a UTF8) para mostrar los nombres correctamente?
James O'Gorman el

Respuestas:

41

Una forma sería con sed:

mv 'file' $(echo 'file' | sed -e 's/[^A-Za-z0-9._-]/_/g')

Reemplace filecon su nombre de archivo, por supuesto. Esto reemplazará cualquier cosa que no sea una letra, número, punto, guión bajo o guión con un guión bajo. Puede agregar o eliminar caracteres para mantenerlos como desee y / o cambiar el carácter de reemplazo a cualquier otra cosa, o nada en absoluto.

James Sneeringer
fuente
44
Yo solía:f='file'; mv 'file' ${f//[^A-Za-z0-9._-]/_}
Louis
1
Busque la mejor solución de H. Hess a continuación ... (y mi comentario divertido al lado :))
Jan Sila
31

Supongo que está en la caja de Linux y los archivos se hicieron en una caja de Windows. Linux usa UTF-8 como codificación de caracteres para los nombres de archivo, mientras que Windows usa algo más. Creo que esta es la causa del problema.

Yo usaría "convmv". Esta es una herramienta que puede convertir nombres de archivos de una codificación de caracteres a otra. Para Europa occidental, uno de estos normalmente funciona:

convmv -r -f windows-1252 -t UTF-8 .
convmv -r -f ISO-8859-1 -t UTF-8 .
convmv -r -f cp-850 -t UTF-8 .

Si necesita instalarlo en un Linux basado en Debian, puede hacerlo ejecutando:

sudo apt-get install convmv

Siempre funciona para mí y recupera el nombre de archivo original.

Fuente: LeaseWebLabs

mevdschee
fuente
1
Esto parece prometedor, pero ¿alguna idea de cómo saber cuál es la codificación? Tengo un directorio llamado Save the current file in Word 97-2004 format\sco.workflowque se creó en mi Mac (a través de Microsoft Office) y las codificaciones anteriores no tienen ningún efecto.
Sridhar Sarnobat
Vale la pena señalar que, por defecto, convmv se ejecuta en modo "prueba", donde solo realiza una ejecución en seco y le dice qué archivos movería. Luego le indicará que vuelva a ejecutarlo con la --notestopción de cambiar el nombre de los archivos.
Kenny Rasschaert
16

¿Supongo que quiere decir que quiere atravesar el sistema de archivos y corregir todos esos archivos?

Así es como lo haría

find /path/to/files -type f -print0 | \
perl -n0e '$new = $_; if($new =~ s/[^[:ascii:]]/_/g) {
  print("Renaming $_ to $new\n"); rename($_, $new);
}'

Eso buscaría todos los archivos con caracteres no ASCII y reemplazaría esos caracteres con guiones bajos ( _). Sin embargo, tenga cuidado, si ya existe un archivo con el nuevo nombre, lo sobrescribirá. El script se puede modificar para verificar un caso así, pero no lo puse para que sea simple.

Patricio
fuente
13

Las siguientes respuestas en https://stackoverflow.com/questions/2124010/grep-regex-to-match-non-ascii-characters , pueden usar:

rename 's/[^\x00-\x7F]//g' *

donde *coincide con los archivos que desea renombrar. Si desea hacerlo en varios directorios, puede hacer algo como:

find . -exec rename 's/[^\x00-\x7F]//g' "{}" \;

Puede usar el argumento -n renamepara hacer una ejecución en seco y ver qué cambiaría, sin cambiarlo.

nada101
fuente
¿Hay alguna forma de modificar esto para mantener caracteres extranjeros como ü y ä por ejemplo?
Elder Geek
Solo el segundo funcionó para mí. Todo estaba en el mismo directorio, así que no estoy seguro de cuál es la diferencia ...
Shautieh
1
@Shautieh: el -n evita que se ejecute realmente. Aclararé la respuesta.
naught101
cambiar el nombre puede ser lento cuando se trata de muchos archivos. Si desea acelerar esto, presione el cheque en buscar. Sin embargo, no estoy seguro de cómo hacerlo.
isaaclw
13

Tenía algunos archivos japoneses con nombres de archivo rotos recuperados de un dispositivo USB roto y las soluciones anteriores no funcionaron para mí.

Recomiendo el paquete de desintoxicación:

La utilidad de desintoxicación cambia el nombre de los archivos para que sea más fácil trabajar con ellos. Elimina espacios y otras molestias. También traducirá o limpiará caracteres Latin-1 (ISO 8859-1) codificados en ASCII de 8 bits, caracteres Unicode codificados en UTF-8 y caracteres escapados CGI.

Ejemplo de uso:

detox -r -v /path/to/your/files
-r Recurrir a subdirectorios
-v Sea detallado acerca de qué archivos se renombran 
-n Se puede usar para una ejecución en seco (solo muestra lo que se cambiaría)
H. Hess
fuente
2
Esto debería ser mucho más alto, insto a todos a echar un vistazo detoxantes de reinventar esencialmente la rueda. Si observa la página de manual, verá que cubre todas las otras soluciones propuestas aquí debido a su flexibilidad.
emk2203
Ezequiel 25:17 - Bienaventurado el que, en nombre de la caridad y la buena voluntad, vota a favor de esta solución, porque es verdaderamente el guardián de su hermano y el buscador de niños perdidos.
Jan Sila
Sin intuición, el camino no puede ser '.' en debian Si usa un '.' No encuentra nada.
isaaclw
Me pregunto si realmente funciona, parece eliminar / reemplazar caracteres chinos, por ejemplo 的节奏啊, pero esos caracteres son nombres de archivo válidos.
皞 皞
5

Este script de shell desinfecta un directorio de forma recursiva, para hacer que los archivos sean portátiles entre Linux / Windows y FAT / NTFS / exFAT. Elimina los caracteres de control /:*?"<>\|y algunos nombres reservados de Windows como COM0.

sanitize() {
  shopt -s extglob;

  filename=$(basename "$1")
  directory=$(dirname "$1")

  filename_clean=$(echo "$filename" | sed -e 's/[\\/:\*\?"<>\|\x01-\x1F\x7F]//g' -e 's/^\(nul\|prn\|con\|lpt[0-9]\|com[0-9]\|aux\)\(\.\|$\)//i' -e 's/^\.*$//' -e 's/^$/NONAME/')

  if (test "$filename" != "$filename_clean")
  then
    mv -v "$1" "$directory/$filename_clean"
  fi
}

export -f sanitize

sanitize_dir() {
  find "$1" -depth -exec bash -c 'sanitize "$0"' {} \;
}

sanitize_dir '/path/to/somewhere'

Linux es menos restrictivo en teoría ( /y \0está estrictamente prohibido en los nombres de archivo), pero en la práctica varios caracteres interfieren con los comandos bash (como *...), por lo que también deben evitarse en los nombres de archivo.

Grandes fuentes para restricciones de nombres de archivos:

KrisWebDev
fuente
1
Es lo que busco! pero agregue comillas para admitir directorios con espacios encuentre "$ 1" -depth -exec bash -c 'sanitize "$ 0"' {} \;
mmv-ru
1

Si desea manejar líneas nuevas incrustadas, caracteres multibyte, espacios, guiones iniciales, barras invertidas y espacios, necesitará algo más robusto, vea esta respuesta:
https://superuser.com/a/858671/365691

Pongo el script en code.google.com si alguien está interesado: rnf-bash-rename-script

A.Danischewski
fuente
El guión vinculado aquí resolvió el problema para mí
Jeremiah Rose el
0

Utilizo esta línea para eliminar caracteres no válidos en los archivos de subtítulos:

for f in *.srt; do nf=$(echo "$f" |sed -e 's/[^A-Za-z0-9.-]/./g;s/\.\.\././g;s/\.\././g'); test "$f" != "$nf" && mv "$f" "$nf" && echo "$nf"; done
  1. Solo procese archivos * .srt (* podría usarse en lugar de * .srt para procesar cada archivo)
  2. Elimina todos los demás caracteres excepto las letras A-Za-z, números 0-9, puntos "." Y guiones "-"
  3. Elimina posibles períodos dobles o triples
  4. Comprueba si el nombre del archivo debe cambiarse
  5. Si es verdadero, cambia el nombre del archivo con el comando mv, luego genera los cambios que realizó con el comando echo

Funciona para normalizar los nombres de directorio de películas:

for f in */; do nf=$(echo "$f" |sed -e 's/[^A-Za-z0-9.]/./g' -e 's/\.\.\././g' -e 's/\.\././g' -e 's/\.*$//'); test "$f" != "$nf" && mv "$f" "$nf" && echo "$nf"; done

Los mismos pasos que arriba pero agregué un comando sed más para eliminar un punto al final del directorio

X-Men Days of Future Past (2014) [1080p]
Modificado a:
X-Men.Days.of.Future.Past.2014.1080p

Brian Kuepper
fuente
-2

para archivo en *; do mv "$ archivo" $ (echo "$ archivo" | sed -e 's / [^ A-Za-z0-9. -] / / g'); hecho &

Jairo Bernal
fuente
2
Debe explicar qué hace su código y usar el formato adecuado. Su código puede hacer que los archivos se eliminen introduciendo colisiones en los nombres. Y ejecutar todo en segundo plano es un poco tonto.
kasperd el