Rellene los nombres de los archivos para que Unix los enumere en orden numérico

Rellene los nombres de los archivos para que Unix los enumere en orden numérico

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 echoantes mvpara 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 envparasus 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].pdfes 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 $fhabrá 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é basenamehace man basenamey 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 printfpara rellenarlo $inty 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, echopor supuesto) el cambio de nombre real usando printf y ordenamos la sustitución nuevamente. printfse usa con 2 %sespecificadores 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 mvpara herramientas externas del bashshell.

#!/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

información relacionada