Kann in bash eine Ganzzahlvariable in der Schleifensteuerung einer for-Schleife verwendet werden?

65

Ich habe das folgende Bash-Skript:

#!/bin/bash

upperlim=10

for i in {0..10}
do
echo $i
done

for i in {0..$upperlim}
do
echo $i
done

Die erste forSchleife ( ohne die Variable upperlimin der Schleifensteuerung) funktioniert einwandfrei, die zweite forSchleife ( mit der Variablen upperlimin der Schleifensteuerung) jedoch nicht. Kann ich die zweite forSchleife so ändern , dass sie funktioniert? Vielen Dank für Ihre Zeit.

Andrew
quelle
4
hm, for i in {0..$((upperlim))}; do echo $i; donegeht auch nicht
Bonsi Scott
und +1, weil ich dieses Verhalten interessant finde
Bonsi Scott
Mögliche Cross-Site-Duplikate von: stackoverflow.com/questions/169511/…
Ciro Santilli
Ein externer Link, der dies beantwortet: cyberciti.biz/faq/…
kon

Antworten:

62

Der Grund dafür ist die Reihenfolge, in der die Dinge in Bash auftreten. Die Klammererweiterung erfolgt, bevor Variablen erweitert werden. Um Ihr Ziel zu erreichen, müssen Sie C-style for loop verwenden:

upperlim=10

for ((i=0; i<=upperlim; i++)); do
   echo "$i"
done
Jordanien
quelle
1
Und funktioniert auch für zsh(aber nicht für csh, tcsh).
Mathe
29

Um dies in Ihrem Stil zu vervollständigen, müssen Sie eval verwenden:

d=12

for i in `eval echo {0..$d}`
do
echo $i
done

Aber mit seq:

lowerlimit=0
upperlimit=12

for i in $(seq $lowerlimit $upperlimit)
do
echo $i
done

Persönlich finde ich die Verwendung seqbesser lesbar.

Jodie C
quelle
Für "eingebaute"? seqist ein externer Befehl und nicht überall dort verfügbar, wo bash ist.
Jordanien
9
@jordanm: Für die Verwendung aller Builtins mit Bash. Dann sagte ich "aber mit seq" und bestätigte, dass es kein eingebautes ist.
Jodie C
Die Tatsache, dass eine Klammererweiterung eingebaut ist, ist hier nicht das Problem. readist ein eingebautes zum Beispiel, aber es gibt keinen Grund evaldafür.
Jordanien
1
Builtins sind überhaupt nicht problematisch. Ich wollte dem Fragesteller eine umfassende Lösung bieten. Wenn Sie weiter darüber streiten möchten, nehmen Sie es mit zum Chat. Kommentare sind nicht gut für so etwas
Jodie C
8

Der POSIX-Weg

Wenn Sie Wert auf Portabilität legen, verwenden Sie das Beispiel aus dem POSIX-Standard :

i=2
END=5
while [ $i -le $END ]; do
    echo $i
    i=$(($i+1))
done

Ausgabe:

2
3
4
5

Dinge die nicht POSIX sind:

Ciro Santilli ist ein Schauspieler
quelle
1

Ihr Ansatz funktioniert nicht, da die Erweiterung in geschweiften Klammern vor der Parametererweiterung erfolgt. Sie müssen die Variable zuvor erweitern.

Sie können mit eval umgehen :

upperlim=10
eval '
        for i in {0..'"$upperlim"'}
        do
                echo $i
        done
'

Mit While-Schleife :

upperlim=10
#with while
start=0
while [[ $start -le $upperlim ]]
do
    echo "$start"
    ((start = start + 1))
done

Sie können dies auch mit dem Befehl seq tun :

upperlim=10
#seq
for i in $(seq "$upperlim"); do
  echo "$i"
done

Wenn Sie mit rennen möchten, müssen for i in {0..$upperlim}Sie Kornshell verwenden. z.B:

#!/bin/ksh
upperlim=10

for i in {0..$upperlim}
do
        echo $i
done
Kheshav Sewnundun
quelle