Shell-Skript "for" -Schleifensyntax


190

Ich habe folgendes zum Arbeiten gebracht:

for i in {2..10}
do
    echo "output: $i"
done

Es produziert eine Reihe von Linien output: 2, output: 3, so weiter.

Versuchen Sie jedoch Folgendes auszuführen:

max=10
for i in {2..$max}
do
    echo "$i"
done

erzeugt folgendes:

output: {2..10}

Wie kann ich den Compiler dazu bringen, zu erkennen, dass er $ max als das andere Ende des Arrays und nicht als Teil eines Strings behandeln soll?


2
Welches System und welche Shell verwenden Sie? Was für ein doofes System hat sh oder bash, aber keine seq, ein Coreutil?
Whatsisname

11
FreeBSD nicht.
Nietzche-jou

echo "$isollte sein echo "$i"- wird das Problem jedoch nicht beheben.
Dave Jarvis

Kleiner Stil nit: Normalerweise werden die Schlüsselwörter dound thenin derselben Zeile wie forund ifangezeigt. ZBfor i in {2..10}; do
ein bezahlter Nerd

Antworten:


232

Die Klammererweiterung {x..y} wird vor anderen Erweiterungen ausgeführt, sodass Sie diese nicht für Sequenzen variabler Länge verwenden können.

Verwenden Sie stattdessen die seq 2 $maxMethode als Benutzer mob angegeben .

Für Ihr Beispiel wäre es also:

max=10
for i in `seq 2 $max`
do
    echo "$i"
done

Es gibt keinen guten Grund, einen externen Befehl zu verwenden, um beispielsweise seqZahlen in der for-Schleife zu zählen und zu erhöhen. Daher wird empfohlen, die Verwendung zu vermeiden seq. Dieser Befehl wird aus Gründen der Kompatibilität mit der alten Bash beibehalten. Die eingebauten Befehle sind schnell genug. for (( EXP1; EXP2; EXP3 )) ...
Müller

13
@miller Die for (( ... ))Syntax ist nicht POSIX und das bedeutet zum Beispiel, dass sie bei Dingen wie Alpine Linux nicht sofort funktioniert. seqtut.
Wernight

@Wernight Nicht nur Alpine Linux; #!/bin/shist Dash in Debian / Ubuntu.
Franklin Yu

72

Probieren Sie die arithmetische Ausdrucksversion von for:

max=10
for (( i=2; i <= $max; ++i ))
do
    echo "$i"
done

Dies ist in den meisten Versionen von Bash verfügbar und sollte auch mit Bourne Shell (sh) kompatibel sein.


1
@Flow: Hm, ich habe es gerade auf einigen Systemen (Linux- und BSD-basiert) mit #! / Bin / sh versucht und es hat gut funktioniert. Aufgerufen unter bash und speziell unter / bin / sh, hat immer noch funktioniert. Vielleicht ist die Version von sh wichtig? Bist du auf einem alten Unix?
System PAUSE

8
Nur sehr wenige Systeme verfügen über eine dedizierte sh, sondern stellen eine Verbindung zu einer anderen Shell her. Im Idealfall wird eine solche Shell aufgerufen, shdie nur diese Funktionen im POSIX-Standard unterstützt, aber standardmäßig einige ihrer zusätzlichen Funktionen durchlässt. Die for-Schleife im C-Stil ist keine POSIX-Funktion, kann jedoch shvon der eigentlichen Shell im Modus sein.
Chepper

27

Schritt die Schleife manuell:

i = 0
max = 10
während [$ i -lt $ max]
machen
    Echo "Ausgabe: $ i"
    true $ ((i ++))
getan

Wenn Sie nicht vollständig POSIX sein müssen, können Sie die arithmetische for- Schleife verwenden:

max = 10
für ((i = 0; i <max; i ++)); Echo "Ausgabe: $ i"; getan

Oder verwenden Sie jot (1) auf BSD-Systemen:

für i in $ (jot 0 10); Echo "Ausgabe: $ i"; getan

3
true $(( i++ ))funktioniert nicht in allen Fällen, daher wären die meisten tragbar true $((i=i+1)).
Flow

Semikolon sollte nicht "für ((i = 0; i <max; i ++))";
Logan

9

Es gibt mehr als einen Weg, dies zu tun.

max=10
for i in `eval "echo {2..$max}"`
do
    echo "$i"
done

7
Ein Sicherheitsrisiko, da alleseval bewertet wird, was Sie eingestellt haben max. Überlegen Sie max="2}; echo ha; #", und ersetzen Sie es echo hadurch etwas Destruktiveres.
Chepper

6
(S) er setzte max auf 10. Kein Risiko.
Conrad Meyer

9

Wenn der seqBefehl auf Ihrem System verfügbar ist:

for i in `seq 2 $max`
do
  echo "output: $i"
done

Wenn nicht, dann benutze arme Männer seqmit perl:

seq=`perl -e "\$,=' ';print 2..$max"`
for i in $seq
do
  echo "output: $i"
done

Beobachten Sie diese Anführungszeichen.


Ich habe das gerade überprüft. es scheint nicht so zu sein.
Eykanal

5

Dies ist ein Weg:
Bash:

max=10
for i in $(bash -c "echo {2..${max}}"); do echo $i; done

Der obige Bash-Weg funktioniert auch für kshund zsh, wenn er bash -cdurch ksh -coder zsh -cersetzt wird.

Hinweis: for i in {2..${max}}; do echo $i; donefunktioniert in zshund ksh.


4

Wir können Schleifen wie bei der C-Programmierung iterieren.

#!/bin/bash
for ((i=1; i<=20; i=i+1))
do 
      echo $i
done

2

Hier funktionierte es unter Mac OS X.

Es enthält das Beispiel eines BSD-Datums, wie das Datum erhöht und verringert wird.

for ((i=28; i>=6 ; i--));
do
    dat=`date -v-${i}d -j "+%Y%m%d"` 
    echo $dat
done

2

Da ich den seqBefehl nicht auf meinem System installiert hatte (Mac OS X 10.6.1 (Snow Leopard)), habe ich stattdessen eine whileSchleife verwendet:

max=5
i=1

while [ $max -gt $i ]
do
    (stuff)
done

* Achselzucken * Was auch immer funktioniert.


2
seq ist relativ neu. Ich habe es erst vor ein paar Monaten erfahren. Sie können aber eine 'for'-Schleife verwenden !! Der Nachteil einer 'Weile' ist, dass Sie daran denken müssen, den Zähler irgendwo innerhalb der Schleife zu erhöhen oder nach unten zu schleifen.
System PAUSE

1

Diese alle tun {1..8}und sollten alle POSIX sein. Sie werden auch nicht unterbrochen, wenn Sie eine Bedingung continuein die Schleife einfügen. Der kanonische Weg:

f=
while [ $((f+=1)) -le 8 ]
do
  echo $f
done

Ein anderer Weg:

g=
while
  g=${g}1
  [ ${#g} -le 8 ]
do
  echo ${#g}
done

und ein anderer:

set --
while
  set $* .
  [ ${#} -le 8 ]
do
  echo ${#}
done

1

Verwenden:

max=10
for i in `eval echo {2..$max}`
do
    echo $i
done

Sie benötigen den expliziten Aufruf 'eval', um das {} nach dem Ersetzen der Variablen neu zu bewerten.

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.