609 Stimmen

Wie man Null-Pad eine Folge von Integer in Bash, so dass alle die gleiche Breite haben?

Ich brauche eine Schleife für einige Werte,

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

Para $first y $last Ich brauche eine feste Länge von 5. Wenn die Eingabe also lautet 1 muss ich Nullen vorangestellt werden, so dass es zu 00001 . Er schleift bis 99999 zum Beispiel, aber die Länge muss 5 sein.

Z.B.: 00002 , 00042 , 00212 , 012312 und so weiter.

Haben Sie eine Idee, wie ich das machen kann?

3voto

Chris Punkte 61

Das wird auch funktionieren:

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

3voto

Zimba Punkte 1969

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

Mit dieser Lösung lassen sich einzelne Zahlen beliebiger Länge oder eine ganze Zahlenfolge mit einer for-Schleife auffüllen/formatieren.

# 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 auf Mac OSX 10.6.8, Bash ver 3.2.48

3voto

harukaeru Punkte 633

TL;DR

$ seq 1 10 | awk '{printf("%05d\n", $1)}'

Eingabe (Muster 1. Langsam):

$ seq 1 10 | xargs -n 1 printf "%05d\n"

Eingabe (Muster 2. Schnell):

$ seq 1 10 | awk '{printf("%05d\n", $1)}'

Ausgabe (jeweils gleiches Ergebnis):

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

説明

Ich würde gerne die oben genannten Muster vorschlagen. Diese Implementierungen können als Befehl verwendet werden, so dass wir sie mit Leichtigkeit wieder verwenden können. Alles, was Sie bei diesen Befehlen beachten müssen, ist die Länge der Zahlen nach der Konvertierung (z.B. Ändern der Zahl %05d in %09d .) Außerdem ist es auch auf andere Lösungen wie die folgende anwendbar. Das Beispiel ist zu abhängig von meiner Umgebung, so dass Ihre Ausgabe könnte anders sein, aber ich denke, Sie können die Nützlichkeit leicht erkennen.

$ wc -l * | awk '{printf("%05d\n", $1)}'
00007
00001
00001
00001
00013
00017
00001
00001
00001
00043

Und so:

$ wc -l * | awk '{printf("%05d\n", $1)}' | sort | uniq
00001
00007
00013
00017
00043

Wenn Sie auf diese Weise schreiben, können wir die Befehle auch asynchron ausführen. (Ich habe einen schönen Artikel gefunden: https://www.dataart.com/en/blog/linux-pipes-tips-tricks )

Haftungsausschluss: Ich bin mir da nicht sicher, und ich bin kein *nix-Experte.

Leistungstest:

Super langsam:

$ time seq 1 1000 | xargs -n 1 printf "%09d\n" > test
seq 1 1000  0.00s user 0.00s system 48% cpu 0.008 total
xargs -n 1 printf "%09d\n" > test  1.14s user 2.17s system 84% cpu 3.929 total

Relativ schnell:

for i in {1..1000}
do
   printf "%09d\n" $i
done
$ time sh k.sh > test
sh k.sh > test  0.01s user 0.01s system 74% cpu 0.021 total

for i in {1..1000000}
do
   printf "%09d\n" $i
done
$ time sh k.sh > test
sh k.sh > test  7.10s user 1.52s system 99% cpu 8.669 total

Schnell:

$ time seq 1 1000 | awk '{printf("%09d\n", $1)}' > test
seq 1 1000  0.00s user 0.00s system 47% cpu 0.008 total
awk '{printf("%09d\n", $1)}' > test  0.00s user 0.00s system 52% cpu 0.009 total

$ time seq 1 1000000 | awk '{printf("%09d\n", $1)}' > test
seq 1 1000000  0.27s user 0.00s system 28% cpu 0.927 total
awk '{printf("%09d\n", $1)}' > test  0.92s user 0.01s system 99% cpu 0.937 total

Wenn Sie eine leistungsfähigere Lösung implementieren müssen, sind wahrscheinlich andere Techniken als das Shell-Skript erforderlich.

1voto

Brauchen Sie nicht awk dafür - entweder seq o jot allein ausreicht:

% seq -f '%05.f' 6     # bsd-seq
00001
00002
00003
00004
00005
00006

% gseq -f '%05.f' 6    # gnu-seq
00001
00002
00003
00004
00005
00006

% jot -w '%05.f' 6
00001
00002
00003
00004
00005
00006

es sei denn, Sie gehen in bigint Gebiet:

% gawk -Mbe '

  function __(_,___) {
      return +_<+___?___:_
  }
  BEGIN {
        _+=_^=_<_                 
      ____="%0*.f\n"   
  } {                      
       ___=__($--_, !+$++_)                
     _____=__(++_+--_, length(______=+$NF)) 
     do {                     
        printf(____,_____,___)
     }  while (___++<______) 

  }' <<< '999999999999999999996 1000000000000000000003'

0999999999999999999996
0999999999999999999997
0999999999999999999998
0999999999999999999999
1000000000000000000000
1000000000000000000001
1000000000000000000002
1000000000000000000003

---------- ---------- ---------- ---------- ----------

Wenn Sie ein Dokument ausdrucken müssen RIESIG Zahlenbereich, dann ist dieser Ansatz vielleicht ein bisschen schneller -

  • Ausdrucken jeder ganzen Zahl von 1 bis 1 Million, links-null-aufgefüllt auf 9 Ziffern, in 0.049s

  • * caveat : Ich hatte nicht die Zeit, alle Eingabebereiche abzudecken :: Es ist nur ein Proof-of-Concept, das Inkremente von Potenzen von 10 akzeptiert

---------- ---------- ---------- ---------- ----------

 ( time ( LC_ALL=C mawk2 '

   function jot(____,_______,_____,_,__,___,______) {
       if(____==(____^!____)) {
           return +____<+_______\
               ? sprintf("%0*.f",_______,____)\
               : +____ 
        }
        _______= (_______-=____=length(____)-\
                 (_=!(_<_)))<+_ \
                 ? "" \
                 : sprintf("%0*.f",_______,!_)
           __=_= (!(__=_+=_+_))(__=(-+--_)+(__+=_)^++_)\
                 (__+=_=(((_--^_--+_++)^++_-_^!_)/_))(__+_)
          _____= "."
     gsub(_____,"\\&&",__)
     ____—-
     do { 
         gsub(_____,__,_)
        _____=_____"." 
     } while(—____)

     gsub(_____,(_______)"&\n",_)
     sub("^[^\n]+[\n]","",_)
     sub(".$",""~"",_______)

     return \
     (_)(_______)\
     sprintf("%0*.f",length(_____),__<__)

   } { print jot($1,$2) }' <<< '10000000 9'

 ) | pvE9 ) |xxh128sum |ggXy3 | lgp3

 sleep 2
 ( time ( LC_ALL=C jot 1000000 | 
          LC_ALL=C mawk2 '{ printf("%09.f\n", $1) }' 

 ) | pvE9 ) |xxh128sum |ggXy3 | lgp3

     out9: 9.54MiB 0:00:00 [ 275MiB/s] [ 275MiB/s] [<=> ]
( LC_ALL=C mawk2  <<< '1000000 9'; )

0.04s user 0.01s system 93% cpu 0.049 total

e0491043bdb4c8bc16769072f3b71f98  stdin

     out9: 9.54MiB 0:00:00 [36.5MiB/s] [36.5MiB/s] [  <=> ]
( LC_ALL=C jot 1000000 | LC_ALL=C mawk2 '{printf("%09.f\n", $1)}'; )

0.43s user 0.01s system 158% cpu 0.275 total

e0491043bdb4c8bc16769072f3b71f98  stdin

Bei 10 Millionen werden die Zeitunterschiede schon spürbar:

 out9: 95.4MiB 0:00:00 [ 216MiB/s] [ 216MiB/s] [<=> ]
 ( LC_ALL=C mawk2  <<< '10000000 9'; )

 0.38s user 0.06s system 95% cpu 0.458 total

 be3ed6c8e9ee947e5ba4ce51af753663  stdin

 out9: 95.4MiB 0:00:02 [36.3MiB/s] [36.3MiB/s] [ <=> ]
 ( LC_ALL=C jot 10000000 | LC_ALL=C mawk2 '{printf("%09.f\n", $1)}'; )

 4.30s user 0.04s system 164% cpu 2.638 total

 be3ed6c8e9ee947e5ba4ce51af753663  stdin

 out9: 95.4MiB 0:00:02 [35.2MiB/s] [35.2MiB/s] [ <=> ]

 ( LC_ALL=C python3 -c '__=1; ___=10**7;

   [ print("{0:09d}".format(_)) for _ in range(__,___+__) ]' 

 ) | pvE9 ) | xxh128sum |ggXy3 | lgp3 ;  )

 2.68s user 0.04s system 99% cpu 2.725 total

 be3ed6c8e9ee947e5ba4ce51af753663  stdin

0voto

nick Punkte 1

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

2.) Wählen Sie außerdem mit "sed -n" die gewünschten Nummern aus (in diesem Fall wählen wir die Nummern 1-100).

3.) jede Zahl 'echo' ausgeben. Die Zahlen werden in der Variablen 'i' gespeichert, auf die mit dem '$' zugegriffen wird.

Pro: Dieser Code ist ziemlich sauber.

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

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X