Come azzerare una sequenza di numeri interi in bash in modo che tutti abbiano la stessa larghezza?


429

Ho bisogno di ripetere alcuni valori,

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

Per $firste $last, ho bisogno che sia di lunghezza fissa 5. Quindi, se l'input è 1, ho bisogno di aggiungere zeri davanti in modo che diventi 00001. Si muove fino 99999ad esempio, ma la lunghezza deve essere 5.

Ad esempio: 00002, 00042, 00212, 012312e così via.

Qualche idea su come posso farlo?


22
Una buona risposta potrebbe essere: seq - w 1 99999. L'opzione -w mantiene costante la lunghezza dell'output, riempiendo i numeri più brevi con 0.
Bruno von Paris,


Molte risposte qui raccomandano, for variable in $(something to generate the numbers); do ...ma questo è problematico quando l'elenco dei numeri è lungo. È molto più efficiente da usare something to generate the numbers | while read -r variable; do .... Vedi anche mywiki.wooledge.org/DontReadLinesWithFor che discute la lettura di righe da file ecc., Ma alcuni degli argomenti si applicano anche qui.
triplo il

Risposte:


712

Nel tuo caso specifico, tuttavia, è probabilmente più semplice utilizzare il -fflag seqper ottenere la formattazione dei numeri mentre genera l'elenco. Per esempio:

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

produrrà il seguente output:

00010
00011
00012
00013
00014
00015

Più in generale, bashha printfcome integrato in modo da poter riempire l'output con zero come segue:

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

È possibile utilizzare il -vflag per memorizzare l'output in un'altra variabile:

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

Nota che printfsupporta un formato leggermente diverso da quello che seqdevi usare al %05dposto di %05g.


5
%05ginvece di %05drisolverlo per me. "00026" mi stava dando "00022" . Grazie!
Ed Manet,

12
Ottima risposta completa. Una piccola correzione: a rigor di termini, seqsupporta un sottoinsieme dei caratteri di formato. che printfsupporta (e che include i sottoinsiemi g, ma non d). Il comportamento dei caratteri de gdifferisce sottilmente in quello che dinterpreta le 0stringhe di numeri prefissate come numeri ottali e le converte in decimali, mentre le gtratta come decimali. (@EdManet: ecco perché '00026' si è trasformato in '00022' con d). Un'altra cosa degna di nota: seq -wfa lo zero padding automatico dei numeri di output in base al numero più largo generato.
mklement0

Questo mi ha aiutato a generare un elenco di caratteri esadecimali. for (( i = 0; i <= 0xffffffff; i++ )) do printf "%08x\n" $i ; done >> hex.txtprodotto un elenco esadecimale di 8 caratteri. Grazie.
cde

seq --help: "FORMATO deve essere adatto per la stampa di un argomento di tipo 'doppio'; il valore predefinito è% .PRECf se FIRST, INCREMENT e LAST sono tutti numeri decimali in virgola fissa con precisione PREC massima e% g in caso contrario." I possibili identificatori di conversione sono efgaEFGA.
x-yuri,

133

Ancora più facile che puoi fare

for i in {00001..99999}; do
  echo $i
done

16
Funziona con Bash versione 4.1.2 (CentOS 6) ma non funziona con la versione 3.2.25 (CentOS 5). Sono d'accordo che questo è un modo molto più esteticamente piacevole per farlo!
Mike Starov,

1
Funziona, ma non dà zero stringhe imbottite sulla mia bash
user2707001,

Su un Mac (Bash 4.4), questo non riempie i numeri. Su CentOS e SuSE, funziona alla grande!
Stefan Lasiewski,

Funziona bene su macOS con Bash4.4.23(1)-release
Whymarrh,

Non funziona neanche su Bash 5 su OS X, purtroppo
gotofritz il

91

Se la fine della sequenza ha una lunghezza massima di riempimento (ad esempio, se vuoi 5 cifre e il comando è "seq 1 10000"), allora puoi usare il flag "-w" per seq - aggiunge il riempimento stesso.

seq -w 1 10

produrre

01
02
03
04
05
06
07
08
09
10

7
Questa è ovviamente la risposta corretta. Perché ha così pochi voti? 😳
adius,

5
facile, perché l'imbottitura dipende dal numero massimo che si desidera raggiungere. Se questo è un parametro che non sai mai in anticipo con quanti zero
finirai

5
Questo non fornisce una lunghezza fissa specificata, ma solo risultati della stessa lunghezza.
Ceisc,

78

usa printf con "% 05d" ad es

printf "%05d" 1

18

Utilizzo molto semplice printf

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

12

Usa awk in questo modo:

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

PRODUZIONE:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

Aggiornare:

Come alternativa bash pura puoi farlo per ottenere lo stesso output:

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

In questo modo puoi evitare di usare un programma esterno seqche NON è disponibile su tutti i tipi di * nix.


1
Possiamo usare la awk's BEGINdichiarazione in modo da non dover usare il heredoccompito.
jaypal singh

@JaypalSingh: Grazie amico, è un buon punto. Aggiornato la mia risposta.
anubhava,

9

Riempo l'output con più cifre (zeri) di quelle di cui ho bisogno, quindi uso tail per usare solo il numero di cifre che sto cercando. Nota che devi usare '6' in coda per ottenere le ultime cinque cifre :)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done

Se si desidera utilizzare il numero corretto di posizioni nell'argomento -c della coda, è possibile utilizzare 'echo -n 00000 $ i' poiché questo lo interrompe producendo una nuova riga che è uno dei caratteri che la coda sta tornando, quindi è necessario essere uno più alto in questa risposta. A seconda di ciò che stai facendo, la nuova riga, se lasciata, potrebbe influire sui risultati.
Ceisc,

L'uso di un processo esterno per tagliare la variabile nel loop è piuttosto inefficiente. È invece possibile utilizzare le funzionalità di espansione dei parametri della shell . In Bash esiste una funzione per estrarre una particolare sottostringa per indice, oppure è possibile utilizzare le sostituzioni prefisso e suffisso con un modello che corrisponde alla larghezza desiderata, sebbene richieda un po 'di avanti e indietro.
triplo il

4

Se si desidera N cifre, aggiungere 10 ^ N ed eliminare la prima cifra.

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

Produzione:

01
02
03
04
05

2

Questo funzionerà anche:

for i in {0..9}{0..9}{0..9}{0..9}
do
  echo "$i"
done

Bella soluzione! Pulito, di facile lettura, non sono necessari programmi aggiuntivi.
Jonathan Cross,

2

Altro modo :

zeroos="000"
echo 

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

Quindi una semplice funzione per convertire qualsiasi numero sarebbe:

function leading_zero(){

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

}

1

Un modo senza usare il fork di processi esterni è la manipolazione delle stringhe, in un caso generico sarebbe simile al seguente:

#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

Funziona abbastanza bene anche su WSL, dove il fork è un'operazione davvero pesante. Avevo un elenco di 110000 file, utilizzando printf "%06d" $NUMimpiegava più di 1 minuto, la soluzione sopra funzionava in circa 1 secondo.


0

1.) Crea una sequenza di numeri 'seq' da 1 a 1000 e fissa la larghezza '-w' (la larghezza è determinata dalla lunghezza del numero finale, in questo caso 4 cifre per 1000).

2.) Inoltre, seleziona quali numeri vuoi usando 'sed -n' (in questo caso, selezioniamo i numeri 1-100).

3.) 'echo' fuori ogni numero. I numeri sono memorizzati nella variabile 'i', cui si accede utilizzando '$'.

Pro: questo codice è abbastanza pulito.

Contro: 'seq' non è nativo di tutti i sistemi Linux (come ho capito)

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

0

Se stai semplicemente riempiendo i numeri con zeri per ottenere una lunghezza fissa, aggiungi il multiplo più vicino di 10, ad es. per 2 cifre, aggiungere 10 ^ 2, quindi rimuovere il primo 1 prima di visualizzare l'output.

Questa soluzione funziona per riempire / formattare singoli numeri di qualsiasi lunghezza o un'intera sequenza di numeri usando un ciclo 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

Testato su Mac OSX 10.6.8, versione di Bash 3.2.48

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.