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?

Eykanal
quelle
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
Whatsisname
quelle
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.

System PAUSE
quelle
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
Nietzche-jou
quelle
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
kurzlebig
quelle
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.

Mob
quelle
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.

Jahid
quelle
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
Hautausschläge
quelle
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
minhas23
quelle
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.

Eykanal
quelle
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

quelle
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.

Chris Dodd
quelle