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/Encoding
ya Motorhead
que 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 find
y 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 echo
el 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í:
-depth
asegurará que los directorios se recreen primero en profundidad, para que podamos "enrollar" todo desde el final. Por lo general, find
atraviesa de manera diferente (pero no primero).
-print0
garantiza que la find
salida esté delimitada por nulos, de modo que podamos leerla read -d ''
en la file
variable. 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
$f
uso 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
$f
ya está limpio (el nombre limpio es idéntico al nombre actual), omítalo.
- Si
$new
ya existe en el directorio $d
(por ejemplo, tiene archivos nombrados resume
y résumé
en el mismo directorio), emita una advertencia. No desea cambiarle el nombre porque, en algunos sistemas, mv foo foo
causa 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öding
de nombre Motorhead/Encoding
se realiza en dos pasos:
mv Motörhead/Encöding Motörhead/Encoding
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 echo
frente 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
, schedule
y test
en sí.
mv
ya existe el destino , lo que puede suceder (1) si tiene archivos que ya están limpios (lo que resulta enmv foo foo
), o (2) si tiene archivos con el mismo nombre excepto para los caracteres especiales (por ejemplo,mv Encöding Encoding
donde ya tiene unEncoding
archivo además deEncöding
).