¿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

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.


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// /_}"' {} \;

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.


1

Uso rename:

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

No hay necesidad de find:)


1
agregue el g final a la expresión regular y funciona perfectamente. 's / \ s / _ / g'
jbrahy

Buen consejo, gracias :)
Jan Werkhoven
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.