web-dev-qa-db-fra.com

Comment utiliser des variables dans une boucle bash for

Comment utilise-t-on une variable dans une boucle bash for? Si j'utilise simplement une boucle standard, elle fait ce que j'attends

for i in {0..3}
do
   echo "do some stuff $i"
done

Cela fonctionne bien. Il boucle à travers 4 fois, de 0 à 3 inclus, imprimant mon message et mettant le décompte à la fin.

do some stuff 0
do some stuff 1
do some stuff 2
do some stuff 3

Lorsque j'essaie la même chose avec la boucle for suivante, il semble égaler une chaîne, ce qui n'est pas ce que je veux.

length=3
for i in {0..$length}
do
   echo "do something right $i"
done

production:

do something right {0..3}

J'ai essayé

for i in {0.."$length"} and for i in {0..${length}} (both output was {0..3})

et

for i in {0..'$length'} (output was {0..$length})

et ils ne font pas tous les deux ce dont j'ai besoin. J'espère que quelqu'un pourra m'aider. Merci à l'avance de l'aide de tout expert bash pour les boucles.

29
Classified

Une façon utilise eval:

for i in $( eval echo {0..$length} )
do
       echo "do something right $i"
done

Remarque ce qui se passe lorsque vous définissez length=;ls ou length=; rm * (n'essayez pas ce dernier cependant).

en toute sécurité, en utilisant seq:

for i in $( seq 0 $length )
do
       echo "do something right $i"
done

ou vous pouvez utiliser la boucle for de style c, qui est également sûre:

for (( i = 0; i <= $length; i++ )) 
do 
       echo "do something right $i"
done
39
perreal

En bash, l'expansion de l'accolade est la première tentative tentée donc, à ce stade, $length ne sera pas remplacé.

La page de manuel de bash indique clairement:

Une expression de séquence prend la forme {x..y [.. incr]}, où x et y sont soit des entiers soit des caractères uniques ...

Il existe un certain nombre de possibilités, telles que l'utilisation:

pax> for i in $(seq 0 $length) ; do echo $i ; done
0
1
2
3

bien que cela puisse vous donner une grande ligne de commande si length est énorme.

Une autre alternative consiste à utiliser la syntaxe de type C:

pax> for (( i = 0; i <= $length; i++ )) ; do echo $i; done
0
1
2
3
7
paxdiablo

Les sous-titres d'accolade sont effectués avant tout autre, vous devez donc utiliser eval ou un outil tiers comme seq.

Exemple pour eval:

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

Ces informations se trouvent en fait dans man bash:

Une expression de séquence prend la forme {x..y [.. incr]}, où x et y sont soit des entiers soit des caractères uniques, et incr, un incrément facultatif, est un entier. [...]

L'expansion d'accolade est effectuée avant toute autre extension, et tout caractère spécial à d'autres extensions est conservé dans le résultat. Il est strictement textuel. Bash n'applique aucune interprétation syntaxique au contexte de l'expansion ou au texte entre les accolades.

3
nemo