
Tengo una carpeta con varios archivos con el siguiente formato:
C Block Scan copy 1.pdf
C Block Scan copy 2.pdf
C Block Scan copy 3.pdf
C Block Scan copy 4.pdf
.
.
.
Un problema que tengo es que cuando ejecuto ls
, Unix los enumera como
C Block Scan copy 1.pdf
C Block Scan copy 10.pdf
C Block Scan copy 11.pdf
C Block Scan copy 12.pdf
.
.
.
Me gustaría rellenar los números para que Unix (con suerte) los enumere en orden como
C Block Scan copy 01.pdf
C Block Scan copy 02.pdf
C Block Scan copy 03.pdf
.
.
.
C Block Scan copy 09.pdf
C Block Scan copy 10.pdf
C Block Scan copy 11.pdf
C Block Scan copy 12.pdf
.
.
.
Encontré una publicación con un problema similar,Rellenar un número en un nombre de archivo a una longitud fija, pero intenté aplicar su solución a mi caso y no pude hacerlo funcionar. Esto es lo que probé:
for f in *.pdf; do
int=`basename $f .pdf | cut -d '.' -f 2`
new_name=`printf "file.%0.2i.pdf\n” $int`
[ ! -f $new_name ] && mv $f $new_name
done
Admito que esta es una adaptación ciega de su solución a mi situación, lo cual no me gusta porque realmente no entiendo la sintaxis subyacente y no tengo un rango lo suficientemente alto en StackExchange para comentar esa publicación todavía. .
Soy nuevo en los scripts de shell, por lo que sería útil y apreciado una explicación de lo que significa la sintaxis.
Si me ayuda, estoy usando macOS Mojave 10.14.6 y tengo Brew instalado.
Gracias de antemano.
Respuesta1
Con zsh
(ahora el shell de usuario predeterminado en macOS):
autoload zmv # best in ~/.zshrc
zmv '(* )([0-9].pdf)' '${1}0$2'
Respuesta2
Esto buscará y cambiará el nombre de todos los archivos "*.pdf" en el directorio actual cuyos nombres sigan el patrón descrito en la pregunta con el mismo nombre pero con un número rellenado con 2 dígitos:
#!/usr/bin/env bash
shopt -s nullglob
for f in *[[:space:]][0-9].pdf; do
int="$(basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1)"
name="$(basename "$f" | rev | cut -d ' ' -f2- | rev)"
padded_int="$(printf "%02d\n" "$int")"
echo mv "$f" "$(printf "%s %s.pdf" "$name" "$padded_int")"
done
Elimínelo echo
antes mv
para ejecutarlo mv
, pero primero ejecútelo como está para asegurarse de que haga lo que desea que haga. Ejemplo de uso con el script anterior guardado en pdf.sh
:
$ for i in {1..10}; do touch "C Block Scan copy $i.pdf"; done
$ ./pdf.sh
mv C Block Scan copy 1.pdf C Block Scan copy 01.pdf
mv C Block Scan copy 2.pdf C Block Scan copy 02.pdf
mv C Block Scan copy 3.pdf C Block Scan copy 03.pdf
mv C Block Scan copy 4.pdf C Block Scan copy 04.pdf
mv C Block Scan copy 5.pdf C Block Scan copy 05.pdf
mv C Block Scan copy 6.pdf C Block Scan copy 06.pdf
mv C Block Scan copy 7.pdf C Block Scan copy 07.pdf
mv C Block Scan copy 8.pdf C Block Scan copy 08.pdf
mv C Block Scan copy 9.pdf C Block Scan copy 09.pdf
La primera línea:
#!/usr/bin/env bash
es unel asunto. Además, lo uso env
parasus caracteristicas.
Esta línea
shopt -s nullglob
conjuntosglobo nulo opción de shell que también se explica en el sitio vinculado:
nullglob
If set, Bash allows filename patterns which match no files to
expand to a null string, rather than themselves.
Es necesario para evitar que se inicie el bucle for si no hay archivos que coincidan con los criterios del patrón:
for f in *[[:space:]][0-9].pdf; do
*[[:space:]][0-9].pdf
es un patrón de shell que significa buscar archivos que tengan nombres compuestos por cualquier número de caracteres seguidos de un espacio en blanco seguido de un solo dígito y que terminen con.pdf. Dentro del bucle $f
habrá un nombre del archivo .pdf procesado.
Aquí
int="$(basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1)"
usamossustitución de comando
para asignar una parte entera del nombre de archivo dado a una variable. Puede ver qué basename
hace man basename
y reproducir la canalización en la terminal:
$ f='C Block Scan copy 1.pdf'
$ echo basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1
1
$ f='C Block Scan copy 5.pdf'
$ echo basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1
5
(Observe que $
aquí hay unsímbolo de línea de comando
se utiliza para indicar el inicio de una nueva línea, no como parte del comando).
En la siguiente línea
name="$(basename "$f" | rev | cut -d ' ' -f2- | rev)"
extraemos la parte del nombre del .pdf, es decir, todo lo que está antes del número.
En la siguiente línea
padded_int="$(printf "%02d\n" "$int")"
Usamos el comando incorporado de Bash printf
para rellenarlo $int
y guardarlo en una variable llamada padded_int
. En la última línea del bucle.
echo mv "$f" "$(printf "%s %s.pdf" "$name" "$padded_int")"
ejecutamos (sin, echo
por supuesto) el cambio de nombre real usando printf
y ordenamos la sustitución nuevamente. printf
se usa con 2 %s
especificadores de formato y 2 argumentos correspondientes, de manera similar a C.
la ultima linea
done
cierra el bucle.
Respuesta3
Usando la expansión de parámetros PE. Sólo mv
para herramientas externas del bash
shell.
#!/usr/bin/env bash
shopt -s nullglob
for f in *[[:space:]][0-9].pdf; do
n=${f##* } ##: Remain only 1.pdf, 2.pdf etc.
n=0${n%.*} ##: Remain only 1 , 2 etc. and pad 0 so it will be 01, 02 ..
echo mv -v "$f" "${f/[0-9]/"$n"}" ##: Replace all [0-9] with the value of "$n"
done