Wie kann eine Folge von Ganzzahlen in Bash auf Null gesetzt werden, damit alle die gleiche Breite haben?


426

Ich muss einige Werte schleifen,

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

Für $firstund $lastmuss es eine feste Länge 5 haben. Wenn die Eingabe also ist 1, muss ich vor Nullen Nullen hinzufügen, damit es wird 00001. Es wiederholt sich 99999zum Beispiel, aber die Länge muss 5 sein.

Zum Beispiel: 00002, 00042, 00212, 012312und so weiter.

Irgendeine Idee, wie ich das machen kann?


22
Eine gute Antwort könnte sein: seq - w 1 99999. Option -w hält die Ausgabelänge konstant und füllt die kürzesten Zahlen mit 0 auf.
Bruno von Paris


Viele Antworten hier empfehlen, for variable in $(something to generate the numbers); do ...aber dies ist problematisch, wenn die Liste der Zahlen lang ist. Es ist viel effizienter zu bedienen something to generate the numbers | while read -r variable; do .... Siehe auch mywiki.wooledge.org/DontReadLinesWithFor, in dem das Lesen von Zeilen aus Dateien usw. erläutert wird. Einige der Argumente gelten jedoch auch hier.
Tripleee

Antworten:


709

In Ihrem speziellen Fall ist es jedoch wahrscheinlich am einfachsten, das -fFlag zu verwenden seq, um die Zahlen bei der Ausgabe der Liste zu formatieren. Zum Beispiel:

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

erzeugt die folgende Ausgabe:

00010
00011
00012
00013
00014
00015

Im Allgemeinen bashist printfeine integrierte Funktion vorhanden, mit der Sie die Ausgabe wie folgt mit Nullen auffüllen können:

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

Mit dem -vFlag können Sie die Ausgabe in einer anderen Variablen speichern:

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

Beachten Sie, dass dies printfein etwas anderes Format unterstützt als das, seqdas Sie %05danstelle von verwenden müssen %05g.


5
%05ganstatt %05des für mich zu reparieren. "00026" gab mir "00022" . Vielen Dank!
Ed Manet

12
Tolle, umfassende Antwort. Eine kleine Korrektur: Streng genommen sequnterstützt sie eine Teilmenge der Formatzeichen. das printfunterstützt (und dass Teilmengen enthält g, aber nicht d). Das Verhalten von Zeichen dund gunterscheidet sich geringfügig darin, dass Zeichenfolgen mit vorfixierten Zahlen als Oktalzahlend interpretiert und in Dezimalzahlen konvertiert werden, während sie als Dezimalzahlen behandelt werden. (@EdManet: Deshalb wurde aus '00026' '00022' mit ). Eine andere Sache , erwähnenswert: tut automatische Zero-Padding der Ausgangszahlen basieren auf einer möglichst großen Zahl erzeugt. 0gdseq -w
mklement0

Dies hat mir geholfen, eine Liste mit Hex-Zeichen zu erstellen. for (( i = 0; i <= 0xffffffff; i++ )) do printf "%08x\n" $i ; done >> hex.txterzeugte eine 8-stellige hexadezimale Liste. Vielen Dank.
cde

seq --help: "FORMAT muss zum Drucken eines Arguments vom Typ 'double' geeignet sein. Der Standardwert ist% .PRECf, wenn FIRST, INCREMENT und LAST Festkomma-Dezimalzahlen mit maximaler Genauigkeit PREC sind, andernfalls% g." Die möglichen Konvertierungsspezifizierer sind efgaEFGA.
X-Yuri

133

Noch einfacher können Sie es einfach tun

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

16
Dies funktioniert unter Bash Version 4.1.2 (CentOS 6), schlägt jedoch in Version 3.2.25 (CentOS 5) fehl. Ich stimme zu, dass dies eine viel ästhetischere Art ist, dies zu tun!
Mike Starov

1
Funktioniert, gibt aber keine null aufgefüllten Zeichenfolgen auf meiner Bash
user2707001

Auf einem Mac (Bash 4.4) werden die Zahlen nicht aufgefüllt. Unter CentOS & SuSE funktioniert es hervorragend!
Stefan Lasiewski

Dies funktioniert gut unter MacOS mit Bash4.4.23(1)-release
Whymarrh

Funktioniert leider auch nicht unter Bash 5 unter OS X
gotofritz

91

Wenn das Ende der Sequenz eine maximale Länge des Auffüllens hat (wenn Sie beispielsweise 5 Ziffern möchten und der Befehl "seq 1 10000" lautet), können Sie das Flag "-w" für seq verwenden - es fügt das Auffüllen selbst hinzu.

seq -w 1 10

produzieren

01
02
03
04
05
06
07
08
09
10

7
Dies ist offensichtlich die richtige Antwort. Warum hat es so wenige positive Stimmen? 😳
Adius

5
einfach, da die Polsterung von der maximalen Anzahl abhängt, die Sie erreichen möchten. Wenn dies ein Parameter ist, wissen Sie nie im Voraus, mit wie vielen Nullen Sie am Ende enden werden
guillem

5
Dies ergibt keine festgelegte Länge, sondern nur Ergebnisse, die alle dieselbe Länge haben.
Ceisc


18

Sehr einfach zu bedienen printf

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

12

Verwenden Sie awk wie folgt:

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

AUSGABE:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

Aktualisieren:

Als reine Bash-Alternative können Sie dies tun, um die gleiche Ausgabe zu erhalten:

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

Auf diese Weise können Sie vermeiden , ein externes Programm zu verwenden, seqdas NICHT für alle Varianten von * nix verfügbar ist .


1
Wir können eine awk's BEGINAnweisung verwenden, damit wir die heredocZuweisung nicht verwenden müssen .
Jaypal Singh

@ JaypalSingh: Danke Kumpel, das ist ein guter Punkt. Meine Antwort wurde aktualisiert.
Anubhava

9

Ich fülle die Ausgabe mit mehr Ziffern (Nullen) auf, als ich brauche, und verwende dann tail, um nur die Anzahl der Ziffern zu verwenden, nach denen ich suche. Beachten Sie, dass Sie '6' im Schwanz verwenden müssen, um die letzten fünf Ziffern zu erhalten :)

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

Wenn Sie die richtige Anzahl von Stellen im Argument -c von tail verwenden möchten, können Sie 'echo -n 00000 $ i' verwenden, da dies die Ausgabe einer neuen Zeile verhindert, die eines der Zeichen ist, die tail zurückgibt, und dies daher erforderlich ist Sei eins höher in dieser Antwort. Je nachdem, was Sie dann tun, kann die neue Zeile, falls sie übrig bleibt, die Ergebnisse beeinflussen.
Ceisc

Die Verwendung eines externen Prozesses zum Trimmen der Variablen in der Schleife ist eher ineffizient. Sie können stattdessen die Parametererweiterungsfunktionen der Shell verwenden. In Bash gibt es eine Möglichkeit, einen bestimmten Teilstring nach Index zu extrahieren, oder Sie können die Präfix- und Suffix-Ersetzungen mit einem Muster verwenden, das der gewünschten Breite entspricht, obwohl ein wenig Hin und Her erforderlich ist.
Tripleee

4

Wenn Sie N Ziffern möchten, fügen Sie 10 ^ N hinzu und löschen Sie die erste Ziffer.

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

Ausgabe:

01
02
03
04
05

2

Dies wird auch funktionieren:

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

Schöne Lösung! Sauber, leicht zu lesen, keine zusätzlichen Programme erforderlich.
Jonathan Cross

2

Andere Weise :

zeroos="000"
echo 

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

Eine so einfache Funktion zum Konvertieren einer beliebigen Zahl wäre:

function leading_zero(){

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

}

0

1.) Erstellen Sie eine Folge von Zahlen 'seq' von 1 bis 1000 und legen Sie die Breite '-w' fest (die Breite wird durch die Länge der Endzahl bestimmt, in diesem Fall 4 Stellen für 1000).

2.) Wählen Sie mit 'sed -n' auch die gewünschten Zahlen aus (in diesem Fall wählen wir die Zahlen 1-100 aus).

3.) Jede Zahl "wiedergeben". Zahlen werden in der Variablen 'i' gespeichert, auf die mit '$' zugegriffen wird.

Vorteile: Dieser Code ist ziemlich sauber.

Nachteile: 'seq' ist nicht für alle Linux-Systeme nativ (soweit ich weiß)

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

0

Wenn Sie nur Zahlen mit Nullen auffüllen möchten, um eine feste Länge zu erreichen, fügen Sie einfach das nächste Vielfache von 10 hinzu, z. Fügen Sie für 2 Ziffern 10 ^ 2 hinzu und entfernen Sie dann die erste 1, bevor Sie die Ausgabe anzeigen.

Diese Lösung dient zum Auffüllen / Formatieren einzelner Zahlen beliebiger Länge oder einer ganzen Folge von Zahlen mithilfe einer for-Schleife.

# 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

Getestet unter Mac OSX 10.6.8, Bash Version 3.2.48


0

Eine Möglichkeit ohne externe Prozessgabelung ist die Manipulation von Zeichenfolgen. In einem generischen Fall würde dies folgendermaßen aussehen:

#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

Dies funktioniert auch bei WSL recht gut, wo das Gabeln eine sehr schwere Operation ist. Ich hatte eine 110000-Dateiliste, printf "%06d" $NUMdie über 1 Minute dauerte, die obige Lösung lief in ca. 1 Sekunde.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.