¿Cómo poner a cero los números del relleno en los nombres de archivos en Bash?
Pregunta
¿Cuál es la mejor manera, usando Bash, de cambiar el nombre de los archivos en el formulario:
(foo1, foo2, ..., foo1300, ..., fooN)
Con nombres de archivos rellenos con ceros:
(foo00001, foo00002, ..., foo01300, ..., fooN)
Solución
En caso N
no está fijado a priori:
for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done
Otros consejos
No es bash puro, pero es mucho más fácil con el rename
dominio:
rename 's/\d+/sprintf("%05d",$&)/e' foo*
Tuve un caso más complejo en el que los nombres de los archivos tenían un sufijo además de un prefijo.También necesitaba realizar una resta del número del nombre del archivo.
Por ejemplo, quería foo56.png
convertirse foo00000055.png
.
Espero que esto ayude si estás haciendo algo más complejo.
#!/bin/bash
prefix="foo"
postfix=".png"
targetDir="../newframes"
paddingLength=8
for file in ${prefix}[0-9]*${postfix}; do
# strip the prefix off the file name
postfile=${file#$prefix}
# strip the postfix off the file name
number=${postfile%$postfix}
# subtract 1 from the resulting number
i=$((number-1))
# copy to a new name with padded zeros in a new folder
cp ${file} "$targetDir"/$(printf $prefix%0${paddingLength}d$postfix $i)
done
El comando oneline que uso es este:
ls * | cat -n | while read i f; do mv "$f" `printf "PATTERN" "$i"`; done
PATRÓN puede ser por ejemplo:
- cambiar el nombre con contador incremental:
%04d.${f#*.}
(mantenga la extensión del archivo original) - cambiar el nombre con contador incremental con prefijo:
photo_%04d.${f#*.}
(mantenga la extensión original) - cambie el nombre con el contador de incrementos y cambie la extensión a jpg:
%04d.jpg
- cambiar el nombre con contador de incrementos con prefijo y nombre base del archivo:
photo_$(basename $f .${f#*.})_%04d.${f#*.}
- ...
Puede filtrar el archivo para cambiarle el nombre, por ejemplo ls *.jpg | ...
Tienes disponible la variable f
ese es el nombre del archivo y i
ese es el mostrador.
Para su pregunta el comando correcto es:
ls * | cat -n | while read i f; do mv "$f" `printf "foo%d05" "$i"`; done
Pure Bash, sin procesos externos distintos de 'mv':
for file in foo*; do
newnumber='00000'${file#foo} # get number, pack with zeros
newnumber=${newnumber:(-5)} # the last five characters
mv $file foo$newnumber # rename
done
Lo siguiente lo hará:
for ((i=1; i<=N; i++)) ; do mv foo$i `printf foo%05d $i` ; done
EDITAR: cambiado para usar ((i=1,...)), gracias mweerden!
Aquí hay una solución rápida que supone un prefijo de longitud fija (su "foo") y un relleno de longitud fija.Si necesita más flexibilidad, tal vez este sea al menos un punto de partida útil.
#!/bin/bash
# some test data
files="foo1
foo2
foo100
foo200
foo9999"
for f in $files; do
prefix=`echo "$f" | cut -c 1-3` # chars 1-3 = "foo"
number=`echo "$f" | cut -c 4-` # chars 4-end = the number
printf "%s%04d\n" "$prefix" "$number"
done
Mi solución reemplaza los números, en todas partes en una cuerda
for f in * ; do
number=`echo $f | sed 's/[^0-9]*//g'`
padded=`printf "%04d" $number`
echo $f | sed "s/${number}/${padded}/";
done
Puede probarlo fácilmente, ya que simplemente imprime nombres de archivos transformados (no se realizan operaciones en el sistema de archivos).
Explicación:
Recorriendo la lista de archivos
Un bucle: for f in * ; do ;done
, enumera todos los archivos y pasa cada nombre de archivo como $f
variable al cuerpo del bucle.
Agarrando el número de la cuerda
Con echo $f | sed
canalizamos la variable $f
a sed
programa.
En comando sed 's/[^0-9]*//g'
, parte [^0-9]*
con modificador ^
le indica que coincida con el dígito opuesto del 0 al 9 (no un número) y luego lo elimine con un reemplazo vacío //
.¿Por qué no simplemente eliminar [a-z]
?Porque el nombre del archivo puede contener puntos, guiones, etc.Entonces, quitamos todo lo que no es un número y obtenemos un número.
A continuación asignamos el resultado a number
variable.Recuerde no poner espacios en la tarea, como number = …
, porque obtienes un comportamiento diferente.
Asignamos el resultado de la ejecución de un comando a una variable, envolviendo el comando con los símbolos de acento grave `.
relleno cero
Dominio printf "%04d" $number
cambia el formato de un número a 4 dígitos y agrega ceros si nuestro número contiene menos de 4 dígitos.
Reemplazo de número por número relleno con ceros
Usamos sed
nuevamente con comando de reemplazo como s/substring/replacement/
.Para interpretar nuestras variables, utilizamos comillas dobles y sustituimos nuestras variables de esta manera. ${number}
.
El script anterior simplemente imprime nombres transformados, así que hagamos el trabajo de cambio de nombre real:
for f in *.js ; do
number=`echo $f | sed 's/[^0-9]*//g'`
padded=`printf "%04d" $number`
new_name=`echo $f | sed "s/${number}/${padded}/"`
mv $f $new_name;
done
Espero que esto ayude a alguien.
Pasé varias horas para resolver esto.
Para rellenar números a la izquierda en los nombres de archivos:
$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 1.zzz
$ for f in [0-9]*.[a-z]*; do tmp=`echo $f | awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;
$ ls -l
total 0
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0001.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:23 0050.zzz
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 010
-rw-r--r-- 1 victoria victoria 0 Mar 28 18:09 050
-rw-r--r-- 1 victoria victoria 0 Mar 28 17:24 10
Explicación
for f in [0-9]*.[a-z]*; do tmp=`echo $f | \
awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;
- tenga en cuenta las comillas invertidas:
`echo ... $2}\`
(La barra invertida, \, inmediatamente arriba simplemente divide esa línea en dos líneas para facilitar la lectura) - en un bucle, busque archivos nombrados como números con extensiones de alfabeto en minúsculas:
[0-9]*.[a-z]*
- repetir ese nombre de archivo (
$f
) para pasarlo aawk
-F.
:awk
separador de campo, un punto (.
):si coincide, separa los nombres de los archivos en dos campos ($1
= número;$2
= extensión)- formato con
printf
:imprimir el primer campo ($1
, la parte numérica) como 4 dígitos (%04d
), luego imprima el período, luego imprima el segundo campo ($2
:la extensión) como una cadena (%s
).Todo eso está asignado a la$tmp
variable - Por último, mueva el archivo fuente (
$f
) al nuevo nombre de archivo ($tmp
)