En bash, est-il possible d'utiliser une variable entière dans le contrôle de boucle d'une boucle for?

65

J'ai le script bash suivant:

#!/bin/bash

upperlim=10

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

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

La première forboucle ( sans la variable upperlimdans le contrôle de boucle) fonctionne correctement, mais pas la deuxième forboucle ( avec la variable upperlimdans le contrôle de boucle). Est-il possible de modifier la seconde forboucle pour qu'elle fonctionne? Merci pour votre temps.

Andrew
la source
4
hm, même for i in {0..$((upperlim))}; do echo $i; donene fonctionne pas
Bonsi Scott
et +1 parce que je trouve ce comportement intéressant
Bonsi Scott
duplication possible sur plusieurs sites de: stackoverflow.com/questions/169511/…
Ciro Santilli a annoncé le
Un lien externe qui répond à cela: cyberciti.biz/faq/…
kon psych

Réponses:

62

La raison en est l’ordre dans lequel les choses se passent pendant le bash. L'expansion d'accolade se produit avant que les variables ne soient développées. Pour atteindre votre objectif, vous devez utiliser le style C pour la boucle:

upperlim=10

for ((i=0; i<=upperlim; i++)); do
   echo "$i"
done
Jordan
la source
1
Et fonctionne pour zshaussi bien (mais pas pour csh, tcsh).
maths le
29

Pour compléter ceci dans votre style en utilisant uniquement des éléments intégrés, vous devez utiliser eval:

d=12

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

Mais avec seq:

lowerlimit=0
upperlimit=12

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

Personnellement, je trouve que l'utilisation de seqest plus lisible.

Jodie C
la source
Pour les "intégrés"? seqest une commande externe et n’est pas disponible partout où bash l’est.
Jordanie
9
@jordanm: Pour utiliser toutes les commandes intégrées avec bash. Puis j'ai dit "mais avec seq", reconnaissant que ce n'était pas intégré.
Jodie C
Le fait que l'expansion de l'accolade soit intégrée n'est pas le problème ici. readest intégré, par exemple, mais il n’ya aucune raison eval.
Jordanie
1
Les bâtis ne sont pas du tout problématiques. Je voulais fournir une solution tout en bash pour le demandeur. Si vous voulez continuer à discuter à ce sujet, prenez-le pour discuter; les commentaires ne sont pas bons pour ce genre de chose
Jodie C
8

La façon POSIX

Si vous vous souciez de la portabilité, utilisez l' exemple du standard POSIX :

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

Sortie:

2
3
4
5

Choses qui ne sont pas POSIX:

Ciro Santilli 改造 中心 六四 事件
la source
1

Votre approche ne fonctionnera pas car, dans Bash, l’expansion se produit avant l’extension des paramètres. Vous devez développer la variable avant.

Vous pouvez contourner eval :

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

Avec boucle While :

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

Vous pouvez aussi le faire avec la commande seq :

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

Si vous voulez courir avec for i in {0..$upperlim}vous devrez utiliser kornshell. par exemple:

#!/bin/ksh
upperlim=10

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