1923 votes

Comment puis-je effectuer une itération sur une plage de numéros définis par des variables en bash?

Comment puis-je effectuer une itération sur une plage de nombres dans bash lorsque l'échelle est donnée par une variable?

Je sais que je peux le faire (appelé "séquence d'expression" dans le bash de la documentation):

 for i in {1..5}; do echo $i; done

Ce qui donne:

1
2
3
4
5

Mais comment puis-je remplacer la gamme des points de terminaison avec une variable? Cela ne fonctionne pas:

END=5
for i in {1..$END}; do echo $i; done

Qui affiche:

{1..5}

2185voto

Jiaaro Points 14379
for i in $(seq 1 $END); do echo $i; done

621voto

ephemient Points 87003

L' seq méthode est la plus simple, mais Bash a intégré dans l'arithmétique de l'évaluation.

END=5
for ((i=1;i<=END;i++)); do
    echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines

Le "for ((expr1;expr2;expr2))" construire des ouvrages comme "for (expr1;expr2;expr3)" en C et langues similaires, et, comme les autres ((expr)) des cas, Bash traite comme de l'arithmétique.

209voto

tzot Points 32224

discussion

À l'aide de seq est très bien, que Jiaaro suggéré. Pax Diablo suggéré une boucle en bash pour éviter d'appeler un sous-processus, avec l'avantage supplémentaire d'être plus de mémoire sympathique si $FIN est trop grand. Zathrus repéré typique d'un bug dans la boucle de la mise en œuvre, et a également laissé entendre que depuis que j'ai est une variable de texte, continue de conversions-et-vient numéros sont effectuées avec un associé ralentissement.

l'arithmétique des nombres entiers

C'est une version améliorée de la boucle en bash:

typeset -i i END
let END=5 i=1
while ((i<=END)); do
    echo $i
    …
    let i++
done

Si la seule chose que nous voulons, c'est l' echo, alors nous pourrions écrire echo $((i++)).

ephemient m'a appris quelque chose: bash for ((expr;expr;expr)) des constructions. Depuis je n'ai jamais lu toute la page de manuel de bash (comme je l'ai fait avec le ksh page de man, et c'était il y a longtemps), j'ai manqué.

Donc,

typeset -i i END # let's be explicit
for ((i=1;i<=END;++i)); do echo $i; done

semble être le plus efficace de la mémoire manière (il ne sera pas nécessaire d'allouer de la mémoire à consommer seqs'sortie, qui pourrait être un problème si la FIN est très grand), mais probablement pas le "le plus rapide".

la question initiale

eschercycle de noter que l' {a..b} bash notation ne fonctionne qu'avec des littéraux; vrai, en conséquence, pour le bash manuel. On peut surmonter cet obstacle avec un seul (interne) fork() sans exec() (comme c'est le cas avec l'appel de seq, ce qui est un autre image nécessite un fork+exec):

for i in $(eval echo "{1..$END}"); do

Les deux eval et echo sont bash objets internes, mais un fork() est nécessaire pour la commande de substitution ( $(…) de construire).

113voto

DigitalRoss Points 80400

Depuis le "comment" de la partie de la question a été complètement répondu, maintenant, je vais commenter pourquoi l'expression d'origine n'a pas fonctionné.

De man bash:

Attelle d'extension est réalisée avant toutes les autres extensions, et tout caractères spéciaux à d'autres les expansions sont conservés dans le résultat. Il est strictement textuelle. Bash ne s'applique pas à toute syntaxique l'interprétation au contexte de l'expansion ou le texte entre les les accolades.

Donc, attelle d'extension est quelque chose comme un purement textuelle macro opération, avant de paramètre d'expansion.

Les coquilles sont hautement optimisé hybrides entre macro processeurs et plus formelle des langages de programmation. Afin d'optimiser l'utilisation typique des cas, la langue est un peu plus complexe et certaines limitations sont acceptés.

36voto

bobbogo Points 4201

Une autre couche d'indirection:

for i in $(eval echo {1..$END}); do
    ∶

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X