Como zerar uma seqüência de números inteiros no bash para que todos tenham a mesma largura?

428

Eu preciso fazer um loop em alguns valores,

for i in $(seq $first $last)
do
    does something here
done

Para $firste $last, eu preciso que ele tenha um comprimento fixo 5. Portanto, se a entrada for 1, eu preciso adicionar zeros na frente para que ela se torne 00001. Faz um loop até, 99999por exemplo, mas o comprimento deve ser 5.

Por exemplo: 00002, 00042, 00212, 012312e assim por diante.

Alguma idéia de como eu posso fazer isso?

John Marston
fonte
22
Uma boa resposta poderia ser: seq - w 1 99999. opção -W mantém constante comprimento de saída, preenchimento números mais curtos com 0.
de Bruno von Paris
Também renomear arquivos: stackoverflow.com/questions/55754/bash-script-to-pad-file-names
Ciro Santilli郝海东冠状病六四事件法轮功
Muitas respostas aqui recomendam, for variable in $(something to generate the numbers); do ...mas isso é problemático quando a lista de números é longa. É muito mais eficiente de usar something to generate the numbers | while read -r variable; do .... Veja também mywiki.wooledge.org/DontReadLinesWithFor, que discute linhas de leitura de arquivos etc, mas alguns dos argumentos se aplicam aqui também.
Tripleee

Respostas:

711

No seu caso específico, embora seja provavelmente mais fácil usar o -fsinalizador seqpara formatar os números à medida que sai da lista. Por exemplo:

for i in $(seq -f "%05g" 10 15)
do
  echo $i
done

produzirá a seguinte saída:

00010
00011
00012
00013
00014
00015

De um modo mais geral, bashpossui printfum built-in para que você possa amortecer a saída com zeros da seguinte maneira:

$ i=99
$ printf "%05d\n" $i
00099

Você pode usar o -vsinalizador para armazenar a saída em outra variável:

$ i=99
$ printf -v j "%05d" $i
$ echo $j
00099

Observe que ele printfsuporta um formato ligeiramente diferente do que seqvocê precisa usar em %05dvez de %05g.

Dave Webb
fonte
5
%05gem vez de %05dconsertar para mim. "00026" estava me dando "00022" . Obrigado!
Ed Manet
12
Ótima resposta abrangente. Uma pequena correção: a rigor, seqsuporta um subconjunto dos caracteres de formato. que printfsuporta (e que subconjuntos inclui g, mas não d). O comportamento dos caracteres de gdifere sutilmente ao dinterpretar 0seqüências de números prefixadas como números octais e convertê- las em decimal, enquanto as gtrata como decimais. (@ EdManet: é por isso que '00026' se transformou em '00022' com d). Outra coisa que vale a pena mencionar: seq -wo preenchimento zero automático dos números de saída com base no número mais amplo gerado.
mklement0
Isso me ajudou a gerar a lista de caracteres hexadecimais. for (( i = 0; i <= 0xffffffff; i++ )) do printf "%08x\n" $i ; done >> hex.txtproduziu uma lista hexadecimal de 8 caracteres. Obrigado.
Cde
seq --help: "FORMAT deve ser adequado para imprimir um argumento do tipo 'double'; o padrão é% .PRECf se PRIMEIRO, INCREMENTO e ÚLTIMO são todos números decimais de ponto fixo com a precisão máxima PREC e% g caso contrário." Os possíveis especificadores de conversão são efgaEFGA.
X-yuri
133

Mais fácil ainda, você pode simplesmente fazer

for i in {00001..99999}; do
  echo $i
done
Indie
fonte
16
Isso funciona no Bash versão 4.1.2 (CentOS 6), mas falha na versão 3.2.25 (CentOS 5). Concordo que esta é uma maneira muito mais esteticamente agradável de fazê-lo!
Mike Starov 13/09/2013
1
Obras, mas não dar zero cordas acolchoados na minha festa
user2707001
Em um Mac (Bash 4.4), isso não preenche os números. No CentOS & SuSE, funciona muito bem!
Stefan Lasiewski
Isso funciona bem no macOS com o Bash4.4.23(1)-release
Whymarrh
Infelizmente, não funciona no Bash 5 no OS X, infelizmente
gotofritz
91

Se o final da sequência tiver comprimento máximo de preenchimento (por exemplo, se você quiser 5 dígitos e o comando for "seq 1 10000"), poderá usar o sinalizador "-w" para seq - ele adicionará o próprio preenchimento.

seq -w 1 10

produzir

01
02
03
04
05
06
07
08
09
10
m_messiah
fonte
7
Esta é obviamente a resposta correta. Por que ele tem tão poucos votos positivos? 😳
adius
5
fácil, porque o preenchimento depende do número máximo que você deseja alcançar. Se este é um parâmetro que você nunca sabe de antemão quantos zero, você vai acabar com
Guillem
5
Isso não fornece um comprimento fixo especificado, apenas resultados com o mesmo comprimento.
Ceisc 25/08
78

use printf com "% 05d", por exemplo

printf "%05d" 1
frankc
fonte
18

Muito simples usando printf

[jaypal:~/Temp] printf "%05d\n" 1
00001
[jaypal:~/Temp] printf "%05d\n" 2
00002
jaypal singh
fonte
12

Use o awk assim:

awk -v start=1 -v end=10 'BEGIN{for (i=start; i<=end; i++) printf("%05d\n", i)}'

RESULTADO:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

Atualizar:

Como alternativa pura do bash, você pode fazer isso para obter a mesma saída:

for i in {1..10}
do
   printf "%05d\n" $i
done

Dessa forma, você pode evitar o uso de um programa externo seqque NÃO está disponível em todos os tipos de * nix.

anubhava
fonte
1
Podemos usar a awk's BEGINdeclaração para não precisarmos usar a heredocatribuição.
jaypal singh
@ JaypalSingh: Obrigado companheiro, esse é um bom ponto. Atualizei minha resposta.
Anubhava
9

Eu preencho a saída com mais dígitos (zeros) do que o necessário e, em seguida, uso tail para usar apenas o número de dígitos que estou procurando. Observe que você precisa usar '6' na cauda para obter os últimos cinco dígitos :)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done
uniforme
fonte
Se você quiser usar o número correto de lugares no argumento -c da cauda, ​​poderá usar 'echo -n 00000 $ i', pois isso impede a saída de uma nova linha que é um dos caracteres que a cauda está retornando, portanto, é necessário seja um mais alto nesta resposta. Dependendo do que você está fazendo, a nova linha, se deixada, pode afetar os resultados.
Ceisc 25/08
Usar um processo externo para aparar a variável no loop é bastante ineficiente. Você pode usar os recursos de expansão de parâmetro do shell . No Bash, existe um recurso para extrair uma substring específica por índice, ou você pode usar as substituições de prefixo e sufixo com um padrão que corresponda à largura desejada, embora exija um pouco de ir e vir.
Tripleee 23/11
4

Se você quiser N dígitos, adicione 10 ^ N e exclua o primeiro dígito.

for (( num=100; num<=105; num++ ))
do
  echo ${num:1:3}
done

Resultado:

01
02
03
04
05
Burghard Hoffmann
fonte
2

Isso funcionará também:

for i in {0..9}{0..9}{0..9}{0..9}
do
  echo "$i"
done
Chris
fonte
Ótima solução! Limpo, fácil de ler, sem a necessidade de programas adicionais.
Jonathan Cross
2

Outro jeito :

zeroos="000"
echo 

for num in {99..105};do
 echo ${zeroos:${#num}:${#zeroos}}${num}
done

Uma função tão simples para converter qualquer número seria:

function leading_zero(){

    local num=$1
    local zeroos=00000
    echo ${zeroos:${#num}:${#zeroos}}${num} 

}
Paco
fonte
1

Uma maneira sem o uso de bifurcação de processo externo é a manipulação de strings, em um caso genérico seria assim:

#start value
CNT=1

for [whatever iterative loop, seq, cat, find...];do
   # number of 0s is at least the amount of decimals needed, simple concatenation
   TEMP="000000$CNT"
   # for example 6 digits zero padded, get the last 6 character of the string
   echo ${TEMP:(-6)}
   # increment, if the for loop doesn't provide the number directly
   TEMP=$(( TEMP + 1 ))
done

Isso funciona muito bem também na WSL, onde a bifurcação é uma operação realmente pesada. Eu tinha uma lista de 110000 arquivos, usando printf "%06d" $NUMdemorou mais de 1 minuto, a solução acima foi executada em cerca de 1 segundo.

Tamisoft
fonte
0

1.) Crie uma sequência de números 'seq' de 1 a 1000 e corrija a largura '-w' (a largura é determinada pelo comprimento do número final, neste caso 4 dígitos para 1000).

2.) Selecione também os números que deseja usar 'sed -n' (nesse caso, selecionamos os números de 1 a 100).

3.) 'ecoam' cada número. Os números são armazenados na variável 'i', acessada usando o '$'.

Prós: Este código é bastante limpo.

Contras: 'seq' não é nativo de todos os sistemas Linux (como eu entendo)

for i in `seq -w 1 1000 | sed -n '1,100p'`; 
do 
    echo $i; 
done
usuario
fonte
0

Se você está logo após preencher números com zeros para obter um comprimento fixo, basta adicionar o múltiplo mais próximo de 10, por exemplo. para 2 dígitos, adicione 10 ^ 2 e remova o primeiro 1 antes de exibir a saída.

Essa solução funciona para preencher / formatar números únicos de qualquer tamanho ou uma sequência inteira de números usando um loop for.

# Padding 0s zeros:
# Pure bash without externals eg. awk, sed, seq, head, tail etc.
# works with echo, no need for printf

pad=100000      ;# 5 digit fixed

for i in {0..99999}; do ((j=pad+i))
    echo ${j#?}
done

Testado no Mac OSX 10.6.8, Bash ver 3.2.48

Zimba
fonte