Como zerar números de teclado em nomes de arquivos no Bash?
Pergunta
Qual é a melhor maneira, usando Bash, de renomear arquivos no formato:
(foo1, foo2, ..., foo1300, ..., fooN)
Com nomes de arquivos preenchidos com zeros:
(foo00001, foo00002, ..., foo01300, ..., fooN)
Solução
Em caso N
não é fixo a priori:
for f in foo[0-9]*; do mv $f `printf foo%05d ${f#foo}`; done
Outras dicas
Não é puro bash, mas é muito mais fácil com o rename
comando:
rename 's/\d+/sprintf("%05d",$&)/e' foo*
Tive um caso mais complexo em que os nomes dos arquivos tinham um postfix e também um prefixo.Também precisei realizar uma subtração do número do nome do arquivo.
Por exemplo, eu queria foo56.png
tornar-se foo00000055.png
.
Espero que isso ajude se você estiver fazendo algo mais complexo.
#!/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
O comando oneline que eu uso é este:
ls * | cat -n | while read i f; do mv "$f" `printf "PATTERN" "$i"`; done
PADRÃO pode ser, por exemplo:
- renomear com contador de incremento:
%04d.${f#*.}
(manter a extensão do arquivo original) - renomear com contador de incremento com prefixo:
photo_%04d.${f#*.}
(manter extensão original) - renomeie com contador de incrementos e altere a extensão para jpg:
%04d.jpg
- renomear com contador de incremento com prefixo e nome de base do arquivo:
photo_$(basename $f .${f#*.})_%04d.${f#*.}
- ...
Você pode filtrar o arquivo para renomear, por exemplo ls *.jpg | ...
Você tem disponível a variável f
esse é o nome do arquivo e i
esse é o contador.
Para sua pergunta o comando certo é:
ls * | cat -n | while read i f; do mv "$f" `printf "foo%d05" "$i"`; done
Pure Bash, nenhum processo externo além 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
O seguinte fará isso:
for ((i=1; i<=N; i++)) ; do mv foo$i `printf foo%05d $i` ; done
EDITAR: alterado para usar ((i=1,...)), obrigado Mweerden!
Aqui está uma solução rápida que assume um prefixo de comprimento fixo (seu "foo") e preenchimento de comprimento fixo.Se precisar de mais flexibilidade, talvez este seja pelo menos um ponto 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
Minha solução substitui números, em todos os lugares de uma string
for f in * ; do
number=`echo $f | sed 's/[^0-9]*//g'`
padded=`printf "%04d" $number`
echo $f | sed "s/${number}/${padded}/";
done
Você pode experimentá-lo facilmente, pois ele apenas imprime nomes de arquivos transformados (nenhuma operação do sistema de arquivos é executada).
Explicação:
Percorrendo a lista de arquivos
Uma volta: for f in * ; do ;done
, lista todos os arquivos e passa cada nome de arquivo como $f
variável para fazer o loop do corpo.
Pegando o número da string
Com echo $f | sed
nós canalizamos variável $f
para sed
programa.
No comando sed 's/[^0-9]*//g'
, papel [^0-9]*
com modificador ^
diz para corresponder ao oposto do dígito 0-9 (não um número) e, em seguida, removê-lo com substituição vazia //
.Por que não apenas remover [a-z]
?Porque o nome do arquivo pode conter pontos, traços, etc.Então, tiramos tudo, que não é um número e pegamos um número.
A seguir, atribuímos o resultado a number
variável.Lembre-se de não colocar espaços na tarefa, como number = …
, porque você obtém um comportamento diferente.
Atribuímos o resultado da execução de um comando à variável, envolvendo o comando com símbolos de crase `.
Preenchimento zero
Comando printf "%04d" $number
altera o formato de um número para 4 dígitos e adiciona zeros se nosso número contiver menos de 4 dígitos.
Substituindo o número por um número preenchido com zeros
Nós usamos sed
novamente com comando de substituição como s/substring/replacement/
.Para interpretar nossas variáveis, usamos aspas duplas e substituímos nossas variáveis desta forma ${number}
.
O script acima apenas imprime nomes transformados, então, vamos fazer o trabalho real de renomeação:
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 isso ajude alguém.
Passei várias horas para descobrir isso.
Para inserir números no teclado esquerdo em nomes de arquivos:
$ 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
Explicação
for f in [0-9]*.[a-z]*; do tmp=`echo $f | \
awk -F. '{printf "%04d.%s\n", $1, $2}'`; mv "$f" "$tmp"; done;
- observe os crases:
`echo ... $2}\`
(A barra invertida, \, imediatamente acima apenas divide essa linha em duas linhas para facilitar a leitura) - em um loop, encontre arquivos nomeados como números com extensões alfabéticas em minúsculas:
[0-9]*.[a-z]*
- ecoe esse nome de arquivo (
$f
) para passá-lo paraawk
-F.
:awk
separador de campos, um ponto (.
):se houver correspondência, separa os nomes dos arquivos como dois campos ($1
= número;$2
= extensão)- formato com
printf
:imprima o primeiro campo ($1
, a parte do número) como 4 dígitos (%04d
), imprima o período e imprima o segundo campo ($2
:a extensão) como uma string (%s
).Tudo isso é atribuído ao$tmp
variável - por último, mova o arquivo de origem (
$f
) para o novo nome do arquivo ($tmp
)