Como criar uma sequência com zeros à esquerda usando expansão de chaves


46

Quando uso o seguinte, obtenho um resultado conforme o esperado:

$ echo {8..10}
8 9 10

Como posso usar essa expansão de chave de maneira fácil, para obter a seguinte saída?

$ echo {8..10}
08 09 10

Eu agora que isso pode ser obtido usando seq(não tentei), mas não é isso que estou procurando.

Informações úteis podem ser que eu estou restrito a esta versão do bash. (Se você tem uma zshsolução, mas não tem bashsolução, compartilhe também)

$ bash -version
GNU bash, version 3.2.51(1)-release (x86_64-suse-linux-gnu)

Alguma dica para fazer isso no bash 3 que encontrei aqui: mywiki.wooledge.org/BashFAQ/018 No entanto, a abordagem descrita não é conveniente.
Bernhard

Respostas:


70

Prefixe o primeiro número com a 0para forçar cada termo a ter a mesma largura.

$ echo {08..10}
08 09 10

Na seção da página de manual do bash na expansão de chaves:

Os números inteiros fornecidos podem ser prefixados com 0 para forçar cada termo a ter a mesma largura. Quando x ou y começam com zero, o shell tenta forçar todos os termos gerados a conter o mesmo número de dígitos, preenchendo o zero quando necessário.

Observe também que você pode usar seqcom a -wopção para equalizar a largura preenchendo os zeros à esquerda:

$ seq -w 8 10
08
09
10

$ seq -s " " -w 8 10
08 09 10

Se você deseja mais controle, pode até especificar um formato de estilo printf:

$ seq -s " " -f %02g 8 10
08 09 10

8
Depois de descobrir a echo {08..10}solução, ela é introduzida apenas para a versão 4 e posterior do bash.
Bernhard

Isso me deixa um pouco desconfortável porque o bash faz isso. Para perlvários utilitários (por exemplo ), um zero à esquerda indica um número octal. Suponho que não é muitas vezes você quer uma sequência de números octais ...
kurtm

5
Deve-se notar que você também pode prefixar os números ao atribuir-lhes seqo -wcomutador da seguinte forma: seq -w 003produz os números 001, 002 e 003.
slm

@kurtm não se preocupe com os zeros à esquerda. Isso pode doer quando algo tenta analisar um número. O que isso realmente é útil é gerar uma sequência de nomes de arquivos em foo_00001.someextensionque quase todos os contextos de classificação forneçam uma ordenação sadia.
Stéphane Gourichon

9

se você usa printf

printf "%.2d " {8..10} 

isso forçará dois caracteres e adicionará um 0. inicial. Caso você precise de 3 dígitos, poderá mudar para "% .3d".


Obrigado pela sua resposta. Estou ciente da printfsolução, mas não está realmente facilitando isso. Eu estou esperando que há algum truque escondido que faz o trabalho :)
Bernhard

Esta é a única resposta que parece versátil o suficiente para lidar com qualquer circunstância de origem do número a ser preenchido. Estou usando um contador enquanto percorre os arquivos. Essa solução de impressão imprime zero sem falhas, enquanto todos os outros parecem se concentrar em gerar números preenchidos com zero, em vez de números existentes com preenchimento zero.
Mightypile

7

Use um intervalo que comece com um dígito constante e retire esse dígito:

echo \ {108..110} | sed 's/ 1//g'

ou sem usar um comando externo:

a=({108..110}); echo "${a[@]#1}"

Para uso em um loop for:

for x in {108..110}; do
  x=${x#1}
  
done

embora, nesse caso, um loop while seja mais claro e funcione em qualquer shell POSIX:

x=8
while [ $x -le 10 ]; do
  n=$((100+x)); n=${n#1}
  
  x=$((x+1))
done

Aceitei esta resposta acima das outras respostas, porque atende à solicitação do Bash 3.x. Especialmente porque eu precisava do forlaço de qualquer maneira.
Bernhard

6

Eu tenho a mesma versão do bash do pôster original ( GNU bash, version 3.2.51(1)-release) e {08..12}não funciona para mim, mas o seguinte:

for i in 0{8..9} {10..12}; do echo $i; done
08
09
10
11
12

É um pouco mais entediante, mas funciona na versão OP do bash (e versões posteriores, eu diria).


Eu não penso sobre esta solução (embora no meu caso eu realmente também quero número 0001 1000, mas suas principais obras, é claro.
Bernhard

1

Para referência, acho que a largura fixa automática ocorre apenas com a versão mais recente do bash:

$ bash -version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

$ echo test{00..05}
test0 test1 test2 test3 test4 test5

-3
for i in $(seq -s " " -f %0${zeros}g $ini $fin); do ....;done

zeros, ini e fin são vars, então é fácil, você escreve apenas zeros que você diz em 'zeros' para ini fin sem problemas;)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.