2117 Stimmen

Wie kann ich in der Bash über einen durch Variablen definierten Zahlenbereich iterieren?

Wie kann ich in Bash über einen Zahlenbereich iterieren, wenn der Bereich durch eine Variable vorgegeben ist?

Ich weiß, dass ich dies tun kann (in der Bash "Sequenzausdruck" genannt) Dokumentation ):

 for i in {1..5}; do echo $i; done

Das ergibt:

1
2
3
4
5

Doch wie kann ich einen der Endpunkte des Bereichs durch eine Variable ersetzen? Das funktioniert nicht:

END=5
for i in {1..$END}; do echo $i; done

Welche Drucke:

{1..5}

41 Stimmen

Hallo zusammen, die Informationen und Tipps, die ich hier gelesen habe, sind alle sehr hilfreich. Ich denke, es ist am besten, die Verwendung von seq zu vermeiden. Der Grund dafür ist, dass einige Skripte portabel sein müssen und auf einer Vielzahl von Unix-Systemen laufen müssen, auf denen einige Befehle möglicherweise nicht vorhanden sind. Nur um ein Beispiel zu nennen: seq ist auf FreeBSD-Systemen standardmäßig nicht vorhanden.

12 Stimmen

Ich weiß nicht mehr, seit welcher Version der Bash genau, aber dieser Befehl unterstützt auch abschließende Nullen. Was manchmal wirklich hilfreich ist. Befehl for i in {01..10}; do echo $i; done würde Zahlen ergeben wie 01, 02, 03, ..., 10 .

41voto

Peter Hoffmann Punkte 52200

Sie können verwenden

for i in $(seq $END); do echo $i; done

37voto

bobbogo Punkte 13969

Eine weitere Ebene der Umleitung:

for i in $(eval echo {1..$END}); do

30voto

Bruno Bronosky Punkte 60135

Ich habe ein paar der hier vorgestellten Ideen kombiniert und die Leistung gemessen.

TL;DR Takeaways:

  1. seq y {..} sind wirklich schnell
  2. for y while Schleifen sind langsam
  3. $( ) ist langsam
  4. for (( ; ; )) Schleifen sind langsamer
  5. $(( )) ist noch langsamer
  6. Besorgnis über N Zahlen im Speicher (seq oder {..}) ist albern (zumindest bis zu 1 Million.)

Diese sind nicht Schlussfolgerungen . Um daraus Schlüsse zu ziehen, müssten Sie sich den C-Code ansehen, der hinter jedem dieser Programme steht. Hier geht es eher darum, wie wir jeden dieser Mechanismen für Schleifen im Code verwenden. Die meisten Einzeloperationen sind nahe genug an der gleichen Geschwindigkeit, dass es in den meisten Fällen keine Rolle spielen wird. Aber ein Mechanismus wie for (( i=1; i<=1000000; i++ )) ist eine Vielzahl von Operationen, wie Sie visuell sehen können. Es sind auch viele weitere Operationen pro Schleife als Sie von for i in $(seq 1 1000000) . Und das ist für Sie vielleicht nicht offensichtlich, weshalb Tests wie dieser so wertvoll sind.

Demos

# show that seq is fast
$ time (seq 1 1000000 | wc)
 1000000 1000000 6888894

real    0m0.227s
user    0m0.239s
sys     0m0.008s

# show that {..} is fast
$ time (echo {1..1000000} | wc)
       1 1000000 6888896

real    0m1.778s
user    0m1.735s
sys     0m0.072s

# Show that for loops (even with a : noop) are slow
$ time (for i in {1..1000000} ; do :; done | wc)
       0       0       0

real    0m3.642s
user    0m3.582s
sys 0m0.057s

# show that echo is slow
$ time (for i in {1..1000000} ; do echo $i; done | wc)
 1000000 1000000 6888896

real    0m7.480s
user    0m6.803s
sys     0m2.580s

$ time (for i in $(seq 1 1000000) ; do echo $i; done | wc)
 1000000 1000000 6888894

real    0m7.029s
user    0m6.335s
sys     0m2.666s

# show that C-style for loops are slower
$ time (for (( i=1; i<=1000000; i++ )) ; do echo $i; done | wc)
 1000000 1000000 6888896

real    0m12.391s
user    0m11.069s
sys     0m3.437s

# show that arithmetic expansion is even slower
$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $i; i=$(($i+1)); done | wc)
 1000000 1000000 6888896

real    0m19.696s
user    0m18.017s
sys     0m3.806s

$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $i; ((i=i+1)); done | wc)
 1000000 1000000 6888896

real    0m18.629s
user    0m16.843s
sys     0m3.936s

$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $((i++)); done | wc)
 1000000 1000000 6888896

real    0m17.012s
user    0m15.319s
sys     0m3.906s

# even a noop is slow
$ time (i=1; e=1000000; while [ $((i++)) -le $e ]; do :; done | wc)
       0       0       0

real    0m12.679s
user    0m11.658s
sys 0m1.004s

25voto

hossbear Punkte 241

Wenn Sie das Präfix brauchen, dann könnte Ihnen das hier gefallen

 for ((i=7;i<=12;i++)); do echo `printf "%2.0d\n" $i |sed "s/ /0/"`;done

das ergibt

07
08
09
10
11
12

21voto

jefeveizen Punkte 474

Wenn Sie unter BSD / OS X arbeiten, können Sie jot statt seq verwenden:

for i in $(jot $END); 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