La pregunta en sí misma tampoco es exacta, porque el OP habla de:
- nombres de archivos como
ABC 123456
(sin extensión), pero en el código de ejemplo que usa *.txt
extensión
- agregue un guión entre dos bloques (por ejemplo, dónde está el espacio) como
ABC - 123456
, pero en la próxima toma counting to 4
y count 3
, por ejemplo, no aclare exactamente qué debe hacer el script, por ejemplo, si encuentra ABCD 12
oAB 345
- Además, quiero mantener el espacio final, lo que es extraño, pero está bien;)
El problema es divisible en 3 partes separadas:
- seleccionando los archivos correctos para cambiar el nombre
- preparar el nuevo nombre de archivo, reemplazar / agregar caracteres al anterior
- el cambio de nombre "físico"
Anuncio "seleccionando los archivos correctos". La selección de los archivos puede ser realizada por algunas utilidades externas, por ejemplo, mediante el find
comando. Los principales beneficios de la find
son:
- también puede buscar archivos de forma recursiva en los subdirectorios
- es posible seleccionar con mayor precisión los archivos correctos, por ejemplo, excluir directorios, seleccionar archivos por tiempo o tamaño, etc. (consultar desde la terminal
man find
)
Anuncio "preparar el nuevo nombre". Esto puede hacerse mediante programas externos, como sed
o awk
cualquier programa que pueda manipular texto en scripts de shell, o puede hacerse (en algunos casos simples como este) dentro de bash
sí mismo, y es posible ahorrar una costosa ejecución de comandos. (para cientos de miles de archivos hace la diferencia).
El seguimiento:
${file/ /-}
sustituye (reemplaza) un espacio (la / /
parte) con el guión ( /-
). Entonces es posible escribir
mv "$file" "${file/ /-}"
y guardar la sed
ejecución.
Entonces, una de las soluciones alternativas podría ser , por ejemplo, la siguiente:
#!/bin/bash
while IFS= read -r -d $'\0' filename
do
newfilename="${filename/ /-}"
[[ "$filename" != "$newfilename" ]] && echo mv -i "$filename" "$newfilename"
done < <(find . -maxdepth 1 -type f -iname "* *.jpg" -print0)
El abobe es para DRY RUN : solo mostrará, lo que se hará, para la ejecución real, elimine el echo
.
Descomposición:
seleccionando los archivos correctos para el cambio de nombre: el find . -maxdepth 1 -type f -iname "* *.jpg" -print0
encontrará todos
- que solo están en el directorio actual (
-maxdepth 1
)
- y son archivos simples (
-type f
)
- y su nombre coincide (cualquier cosa) (espacio) (cualquier cosa) .jpg mayúsculas y minúsculas - por ejemplo, el nombre debe contener un espacio
- proporcione los nombres de archivo como nulos terminados , por lo que su nombre también puede contener de forma segura el carácter de nueva línea. (
-print0
)
el ciclo while IFS= read -r -d $'\0' filename; do ... done < <( )
- lee el resultado del
find
comando anterior
- donde los nombres de archivo son nulos terminados (
-d $'\0'
)
- ignorar los caracteres escapados (
-r
) / tema avanzado - no es necesario explicarlo aquí /
- los
IFS=
previene de recorte del espacio inicial y final del nombre de archivo (también, un tema avanzado poco)
preparar el nuevo nombre de archivo newfilename="${filename/ /-}"
- se realiza
bash
internamente (sin ejecutar un comando externo).
- si desea preservar el espacio final después del uso del guión
${filename/ /- }
el cambio de nombre real se realiza mediante el mv
comando (ver man mv
desde la terminal), donde
- el
-i
lo que le preguntará al usuario si ya están aquí un archivo con el nuevo nombre de archivo (no anularlo)
y el mv
se ejecuta solo cuando el newfilename
es diferente delfilename
[[ "$filename" != "$newfilename" ]]
La solución anterior es en su mayoría propensa a errores, pero aún así no es muy efectiva, porque para cientos de miles de archivos ejecutará cientos de miles de veces el mv
comando. La solución puede ser: usar alguna utilidad, lo que puede leer los nombres de archivo y cambiar el nombre sin ejecutar el mv
comando N-times. Por ejemplo, la "gran arma" del sistema administra el "perl", como:
find . -maxdepth 1 -type f -iname "*.jpg" -print0 |\
perl -0nle '$n=$_; $n=~s/ /-/; rename $_,$n unless($_ eq $n || -e $n)'
lo que cambiará el nombre de todos los archivos lo que generará find
en una ejecución, por ejemplo, mucho más rápido que miles de mv
ejecuciones.
Las pruebas Tor (DRY RUN) usan lo siguiente:
find . -maxdepth 1 -type f -iname "*.jpg" -print0 |\
perl -0nle '$n=$_; $n=~s/ /-/; print qq{old:$_ new:$n\n} unless($_ eq $n || -e $n)' #print instead of the rename
Ps: el perl es lo suficientemente poderoso como para manejar todo por sí mismo, por ejemplo. el comando find también, pero es un tema más avanzado ...
Ps2: mi inglés es mucho peor que el mío bash
, por lo que alguien podría editar esta publicación para agregar / corregir cosas ...;)