¿Cómo reemplazar espacios en todos los nombres de archivo con guiones bajos en Linux usando el script de shell?

17

Intenté seguir el script de shell que debería reemplazar los espacios de todos los nombres de archivos xml

for xml_file in $(find $1 -name "* .xml" -type f);
do
 echo "removing spaces from XML file:" $xml_file
 mv "$xml_file" "${xml_file// /_}";
done

Supongamos que tengo un archivo xml con el nombre xy z.xml, luego da:

removing spaces from XML file: /home/krishna/test/xy
mv: cannot stat `/home/krishna/test/xy': No such file or directory
removing spaces from XML file: .xml
mv: cannot stat `z.xml': No such file or directory
Krishna
fuente

Respuestas:

28

Use esto con bash:

find $1 -name "* *.xml" -type f -print0 | \
  while read -d $'\0' f; do mv -v "$f" "${f// /_}"; done

findbuscará archivos con un espacio en el nombre. Los nombres de archivo se imprimirán con un nulobyte ( -print0) como delimitador para hacer frente también a nombres de archivo especiales. Luego, el readarchivo incorporado lee los nombres de archivo delimitados por el nulobyte y finalmente mvreemplaza los espacios con un guión bajo.

EDITAR: si también desea eliminar los espacios en los directorios, es un poco más complicado. Los directorios se renombran y luego ya no se puede acceder por los nombres findencontrados. Prueba esto:

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

El sort -rzinvierte el orden de los archivos, por lo que los archivos más profundos en una carpeta es el primero en mover y la propia carpeta será la última. Por lo tanto, nunca hay carpetas renombradas antes de que todos los archivos y carpetas cambien de nombre dentro de ella. El mvcomando en el bucle también ha cambiado un poco. En el nombre de destino, solo eliminamos los espacios en el nombre base del archivo, de lo contrario no sería accesible.

caos
fuente
Estoy tratando de reemplazar espacios con guiones bajos en todo el directorio, pero está dando un error porque después de cambiar el nombre ese directorio no es accesible.
Krishna
@ Krishna Agregué una edición a mi respuesta.
caos
1
@chaos wow, acabo de ejecutar estos dos en dos sistemas y funcionó de maravilla, pocos archivos y directorios no se ejecutan, pero son solo unos pocos
algo
En macOS necesitamos especificar el directorio en el comando de búsqueda antes de la opción -name find . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter
17
  1. Utilizando rename

    find . -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;

    o con $1

    find "$1" -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;
  2. Utilizando mv

    find . -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

    o con $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;
AB
fuente
No sé por qué, pero tu comando dado no funciona para mí. No muestra ningún error y salida.
Krishna
@krishna corregido, lo siento
AB
1
Rename funcionó para mí. ¡Golpe de puños!
Brian Piercy el
1

Este es un método que encontré al enfrentar el mismo problema:

for f in *; do mv "$f" `echo $f | tr ' ' '_'`; done

Estaba escribiendo un archivo de script bash para actualizar automáticamente mis certificados SSL.

NekoMisaki
fuente
1

Uso rename:

rename 's/\s/_/g' ./*.xml

No hay necesidad de find:)

Jan Werkhoven
fuente
1
agregue el g final a la expresión regular y funciona perfectamente. 's / \ s / _ / g'
jbrahy
Buen consejo, gracias :)
Jan Werkhoven