¿Secuencia de comandos de Shell para corregir nombres de archivos incorrectos?

¿Secuencia de comandos de Shell para corregir nombres de archivos incorrectos?

Soy TI en mi pequeña empresa; y, a pesar de mis terribles advertencias, todo el mundo coloca archivos en el servidor con nombres horribles, incluidos espacios iniciales y finales, caracteres incorrectos (¡incluidos, \ ; / + . < > -etc.!)

Lo hacen accediendo al servidor (FreeBSD/FreeNAS) a través de AFP en Mac, por lo que ninguna parte del sistema se queja.

¿Existe algún script que pueda utilizar para recorrer un árbol de directorios completo y corregir nombres de archivos incorrectos?

Básicamente, reemplace todos los espacios y el ASCII incorrecto con _... y si ya existe un archivo, simplemente coloque _2algo al final.

Supongo que no hay una manera de hacer que el sistemahacer cumplirBuenas convenciones de nombres de archivos, ¿verdad?

¡Gracias!

Respuesta1

Usaría bash y buscaría. Estoy seguro de que hay una opción más sencilla, pero esto es lo que se me ocurrió:

  1. Esto puede tratar con nombres de archivos que contienen "/" (buscar dará una advertencia, ignórelo), perosolo funcionará en archivos en el directorio actual(sin subdirectorios). No pude entender cómo decirle a bash o find diferenciar entre un "/" en un nombre de archivo y un "/" que es parte de la ruta.

    for i in $(find . -maxdepth 1 -type f  -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" | sed 's/\.\///'); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}; done
    
  2. Ésteno puedoTratar con nombres de archivos que contienen "/" pero funcionará en todos los archivos en el directorio actual.y sus subdirectorios:

    for i in $(find . -type f  -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%]/_}; done
    

Asegurate quePruébelos antes de ejecutar. Funcionaron bien en las pocas pruebas que realicé, pero no fui exhaustivo. También tenga en cuenta que estoy en un sistema Linux. La implementación particular de find, y quizás bash, puede diferir de la suya.


EDITAR: Cambiar el mv $icomando a `mv -i $i' hará que mv le avise antes de sobrescribir un archivo existente.

EDITAR2: Para tratar nombres de archivos con espacios, puede cambiar la variable bash IFS (Separador de campo de entrada) así (adaptado deaquí):

SAVEIFS=$IFS; IFS=$(echo -en "\n\b"); for i in $(find . -type f  -name "*[\:\;\>\<\@\$\#\&\(\)\?\\\%\ ]*"); do mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\%\ ]/_}; done; IFS=$SAVEIFS

También modifiqué la expresión regular para hacer coincidir/reemplazar espacios con guiones bajos. El bit SAVEIFS simplemente devuelve la variable IFS a su configuración original.


EXPLICACIÓN:

for i in $(command); do something $i; done

Este es un bucle bash genérico. Revisará la salida de un comando, configurando secuencialmente la variable $i para cada uno de los valores devueltos por el comando, y le hará algo.


find . -maxdepth 1 -type f  -name "*[\:\;><\@\$\#\&\(\)\?\\\/\%]*" '

Busque todos los archivos en el directorio actual cuyo nombre contenga uno de los siguientes caracteres: :;><@$#&()\/%. Para agregar más, simplemente escápelos con "\" (por ejemplo, "\¿") y agréguelos a la lista entre corchetes ([ ]). Probablemente, no es necesario escapar de todos estos personajes, pero nunca puedo recordar cuáles son variables especiales en qué entorno, así que escape de todo, por si acaso.

sed 's/\.\///

Elimine el directorio actual de la salida de búsqueda, imprima "foo" en lugar de "./foo".

mv "$i" ${i//[\;><\@\$\#\&\(\)\?\\\/\%]/_}

Cada vez que este pequeño fragmento se repite, $i será el nombre de un archivo con un nombre incorrecto. Este comando moverá (cambiará el nombre) ese archivo cambiando todos los caracteres no deseados a "_". Busque sustitución de bash para obtener más información.


información relacionada