Comment puis-je itérer sur une plage de nombres définis par des variables dans Bash?


1545

Comment puis-je itérer sur une plage de nombres dans Bash lorsque la plage est donnée par une variable?

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

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

Qui donne:

1
2
3
4
5

Pourtant, comment puis-je remplacer l'un des points de terminaison de plage par une variable? Cela ne fonctionne pas:

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

Qui imprime:

{1..5}


26
Bonjour à tous, les informations et les conseils que j'ai lus ici sont tous très utiles. Je pense qu'il est préférable d'éviter l'utilisation de seq. La raison en est que certains scripts doivent être portables et doivent s'exécuter sur une grande variété de systèmes Unix, où certaines commandes peuvent ne pas être présentes. Juste pour faire un exemple, seq n'est pas présent par défaut sur les systèmes FreeBSD.


9
Je ne me souviens pas depuis quelle version de Bash exactement, mais cette commande prend également en charge les zéros de fin. Ce qui est parfois très utile. La commande for i in {01..10}; do echo $i; donedonnerait des nombres comme 01, 02, 03, ..., 10.
topr

1
Pour ceux comme moi qui veulent simplement parcourir la plage d'indices d'un tableau , la méthode bash serait: myarray=('a' 'b' 'c'); for i in ${!myarray[@]}; do echo $i; done(notez le point d'exclamation). C'est plus précis que la question d'origine, mais cela pourrait aider. Voir les extensions de paramètres bash
PlasmaBinturong

1
L'expansion d'accolade est également utilisée pour des expressions comme celles {jpg,png,gif}qui ne sont pas directement traitées ici, bien que la réponse soit identique. Voir Expansion Brace avec variable? [duplicate] qui est marqué comme un double de celui-ci.
tripleee

Réponses:


1747
for i in $(seq 1 $END); do echo $i; done

edit: je préfère seqles autres méthodes car je m'en souviens;)


36
seq implique l'exécution d'une commande externe qui ralentit généralement les choses. Cela n'a peut-être pas d'importance, mais cela devient important si vous écrivez un script pour gérer de nombreuses données.
paxdiablo

37
Très bien pour une doublure. La solution de Pax est très bien aussi, mais si les performances étaient vraiment un problème, je n'utiliserais pas de script shell.
eschercycle

17
seq est appelé une seule fois pour générer les nombres. exec () ne devrait être significatif que si cette boucle se trouve dans une autre boucle serrée.
Javier

29
La commande externe n'est pas vraiment pertinente: si vous vous inquiétez de la surcharge d'exécution de commandes externes, vous ne voulez pas du tout utiliser de scripts shell, mais généralement sous unix, la surcharge est faible. Cependant, il y a le problème de l'utilisation de la mémoire si END est élevé.
Mark Baker

18
Notez que seq $ENDcela suffirait, car la valeur par défaut est de partir de 1. De man seq: "Si FIRST ou INCREMENT est omis, il est par défaut 1".
fedorqui 'SO arrête de nuire'

475

La seqméthode est la plus simple, mais Bash a une évaluation arithmétique intégrée.

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

La for ((expr1;expr2;expr3));construction fonctionne comme for (expr1;expr2;expr3)en C et dans des langages similaires, et comme dans d'autres ((expr))cas, Bash les traite comme de l'arithmétique.


68
De cette façon, vous évitez la surcharge de mémoire d'une grande liste et une dépendance sur seq. Utilise le!
bobbogo

3
@MarinSagovac Cela fait travail et il n'y a pas d' erreur de syntaxe. Êtes-vous sûr que votre coquille est Bash?
gniourf_gniourf

3
@MarinSagovac Assurez-vous de faire #!/bin/bashla première ligne de votre script. wiki.ubuntu.com/…
Melebius

7
juste une très courte question à ce sujet: pourquoi ((i = 1; i <= END; i ++)) ET NON ((i = 1; i <= $ END; i ++)); pourquoi pas $ avant END?
Baedsch

5
@Baedsch: pour la même raison, i n'est pas utilisé comme $ i. Les états de la page de manuel de bash pour l'évaluation arithmétique: "Dans une expression, les variables shell peuvent également être référencées par leur nom sans utiliser la syntaxe d'expansion des paramètres."
user3188140

193

discussion

L'utilisation seqest très bien, comme l'a suggéré Jiaaro. Pax Diablo a suggéré une boucle Bash pour éviter d'appeler un sous-processus, avec l'avantage supplémentaire d'être plus convivial en mémoire si $ END est trop grand. Zathrus a repéré un bogue typique dans l'implémentation de la boucle et a également laissé entendre que puisqu'il is'agit d'une variable de texte, des conversions continues de nombres en va-et-vient sont effectuées avec un ralentissement associé.

arithmétique entière

Il s'agit d'une version améliorée de la boucle 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 est la echo, alors nous pourrions écrire echo $((i++)).

L'éphémient m'a appris quelque chose: Bash autorise les for ((expr;expr;expr))constructions. Comme je n'ai jamais lu toute la page de manuel de Bash (comme je l'ai fait avec la kshpage de manuel Korn shell ( ), et c'était il y a longtemps), j'ai raté cela.

Donc,

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

semble être le moyen le plus économe en mémoire (il ne sera pas nécessaire d'allouer de la mémoire pour consommer seqla sortie de, ce qui pourrait être un problème si END est très volumineux), bien que ce ne soit probablement pas le «plus rapide».

la question initiale

eschercycle a noté que la notation { a .. b } Bash ne fonctionne qu'avec des littéraux; vrai, conformément au manuel de Bash. On peut surmonter cet obstacle avec un seul (interne) fork()sans un exec()(comme c'est le cas avec les appels seq, qui étant une autre image nécessite un fork + exec):

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

Les deux evalet echosont des commandes intégrées Bash, mais un fork()est requis pour la substitution de commande (la $(…)construction).


1
Le seul inconvénient de la boucle de style C est qu'elle ne peut pas utiliser d'arguments de ligne de commande, car ils commencent par "$".
karatedog

3
@karatedog: for ((i=$1;i<=$2;++i)); do echo $i; donedans un script fonctionne très bien pour moi sur bash v.4.1.9, donc je ne vois pas de problème avec les arguments de la ligne de commande. Voulez-vous dire autre chose?
tzot

Il semble que la solution eval soit plus rapide que celle construite en C pour: $ time for ((i = 1; i <= 100000; ++ i)); faire :; done real 0m21.220s user 0m19.763s sys 0m1.203s $ time for i in $ (eval echo "{1..100000}"); faire :; terminé; réel 0m13.881s utilisateur 0m13.536s sys 0m0.152s
Marcin Zaluski

3
Oui, mais eval est mauvais ... @MarcinZaluski time for i in $(seq 100000); do :; doneest beaucoup plus rapide!
F.Hauri

Les performances doivent être spécifiques à la plate-forme car la version eval est la plus rapide sur ma machine.
Andrew Prock

103

Voici pourquoi l'expression originale n'a pas fonctionné.

De l' homme bash :

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

Ainsi, l' expansion d'accolade est quelque chose qui se fait tôt comme une opération de macro purement textuelle, avant l' expansion des paramètres.

Les shells sont des hybrides hautement optimisés entre les macro-processeurs et les langages de programmation plus formels. Afin d'optimiser les cas d'utilisation typiques, le langage est rendu plus complexe et certaines limitations sont acceptées.

Recommandation

Je suggère de rester avec les fonctionnalités de Posix 1 . Cela signifie utiliser for i in <list>; do, si la liste est déjà connue, sinon, utiliser whileou seq, comme dans:

#!/bin/sh

limit=4

i=1; while [ $i -le $limit ]; do
  echo $i
  i=$(($i + 1))
done
# Or -----------------------
for i in $(seq 1 $limit); do
  echo $i
done


1. Bash est un excellent shell et je l'utilise de manière interactive, mais je ne mets pas de bash-isms dans mes scripts. Les scripts peuvent avoir besoin d'un shell plus rapide, plus sécurisé, plus intégré. Ils peuvent avoir besoin de s'exécuter sur tout ce qui est installé sous / bin / sh, et puis il y a tous les arguments pro-standards habituels. Rappelez-vous shellshock, alias bashdoor?


13
Je n'ai pas le pouvoir, mais je déplacerais cela un peu vers le haut de la liste, surtout le bash nombril, mais immédiatement après le style C pour l'évaluation en boucle et arithmétique.
matelot

2
Une implication est que l'expansion d'accolade n'économise pas beaucoup de mémoire par rapport à seqde grandes plages. Par exemple, echo {1..1000000} | wcrévèle que l'écho produit 1 ligne, un million de mots et 6 888 896 octets. Essayer seq 1 1000000 | wcdonne un million de lignes, un million de mots et 6 888 896 octets et est également plus de sept fois plus rapide, tel que mesuré par la timecommande.
George

Remarque: j'avais déjà mentionné la whileméthode POSIX dans ma réponse: stackoverflow.com/a/31365662/895245 Mais content que vous soyez d'accord :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

J'ai inclus cette réponse dans ma réponse de comparaison des performances ci-dessous. stackoverflow.com/a/54770805/117471 (Ceci est une note pour moi de garder une trace de ceux qu'il me reste à faire.)
Bruno Bronosky

@mateor Je pensais que le style C pour l'évaluation en boucle et l'arithmétique était la même solution. Suis-je en train de manquer quelque chose?
Oscar Zhang

73

La façon POSIX

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

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

Production:

2
3
4
5

Choses qui ne sont pas POSIX:


Je viens d'avoir 4 votes positifs sur cette réponse, ce qui est très inhabituel. Si cela a été publié sur un site Web d'agrégation de liens, donnez-moi un lien, merci.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

La citation fait référence à x, et non à l'expression entière. $((x + 1))est très bien.
chepner

Bien qu'ils ne soient pas portables et diffèrent de GNU seq(BSD seqvous permet de définir une chaîne de terminaison de séquence avec -t), FreeBSD et NetBSD ont également seqdepuis 9.0 et 3.0, respectivement.
Adrian Günter

@CiroSantilli @chepner $((x+1))et $((x + 1))parse exactement le même, que lorsque l'analyseur tokenizes x+1il sera divisé en 3 jetons: x, +et 1. xn'est pas un jeton numérique valide, mais c'est un jeton de nom de variable valide, mais x+ne l'est pas, d'où la division. +est un jeton d'opérateur arithmétique valide, mais +1ne l'est pas, donc le jeton y est de nouveau divisé. Et ainsi de suite.
Adrian Günter

J'ai inclus cette réponse dans ma réponse de comparaison des performances ci-dessous. stackoverflow.com/a/54770805/117471 (Ceci est une note pour moi de garder une trace de ceux qu'il me reste à faire.)
Bruno Bronosky

35

Une autre couche d'indirection:

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

2
+1: Évaluez également 'pour i dans {1 ..' $ END '}; do ... 'eval semble le moyen naturel de résoudre ce problème.
William Pursell

28

Vous pouvez utiliser

for i in $(seq $END); do echo $i; done

seq implique l'exécution d'une commande externe qui ralentit généralement les choses.
paxdiablo

9
Cela n'implique pas l'exécution d'une commande externe pour chaque itération, une seule fois. Si le temps de lancer une commande externe est un problème, vous utilisez la mauvaise langue.
Mark Baker

1
L'imbrication est-elle donc le seul cas où cela importe? Je me demandais s'il y avait une différence de performances ou un effet secondaire technique inconnu?
Sqeaky

@Squeaky C'est une question distincte à laquelle il est répondu ici: stackoverflow.com/questions/4708549/…
tripleee

J'ai inclus cette réponse dans ma réponse de comparaison des performances ci-dessous. stackoverflow.com/a/54770805/117471 (Ceci est une note pour moi de garder une trace de ceux qu'il me reste à faire.)
Bruno Bronosky

21

Si vous en avez besoin, préférez-vous

 for ((i=7;i<=12;i++)); do echo `printf "%2.0d\n" $i |sed "s/ /0/"`;done

cela donnera

07
08
09
10
11
12

4
Ce ne serait pas printf "%02d\n" $iplus simple que ça printf "%2.0d\n" $i |sed "s/ /0/"?
zb226

19

Si vous êtes sur BSD / OS X, vous pouvez utiliser jot au lieu de seq:

for i in $(jot $END); do echo $i; done

17

Cela fonctionne bien dans bash:

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

6
echo $((i++))fonctionne et le combine sur une seule ligne.
Bruno Bronosky

1
Cela a des extensions bash inutiles. Une version POSIX: stackoverflow.com/a/31365662/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@Ciro, puisque la question indique spécifiquement bash, et a une balise bash, je pense que vous trouverez probablement que les 'extensions' bash sont plus que correctes :-)
paxdiablo

@paxdiablo Je ne veux pas dire que ce n'est pas correct, mais pourquoi ne pas être portable quand nous le pouvons ;-)
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

Dans bash, nous pouvons simplement faire while [[ i++ -le "$END" ]]; dopour faire l'incrémentation (post-) dans le test
Aaron McDaid

14

J'ai combiné quelques idées ici et mesuré les performances.

TL; DR Points à retenir:

  1. seqet {..}sont vraiment rapides
  2. foret les whileboucles sont lentes
  3. $( ) est lent
  4. for (( ; ; )) les boucles sont plus lentes
  5. $(( )) est encore plus lent
  6. S'inquiéter des nombres N en mémoire (seq ou {..}) est idiot (au moins jusqu'à 1 million.)

Ce ne sont pas des conclusions . Vous devriez regarder le code C derrière chacun d'eux pour tirer des conclusions. C'est plus sur la façon dont nous avons tendance à utiliser chacun de ces mécanismes pour boucler le code. La plupart des opérations individuelles sont suffisamment proches pour avoir la même vitesse que cela n'aura pas d'importance dans la plupart des cas. Mais un mécanisme comme de for (( i=1; i<=1000000; i++ ))nombreuses opérations comme vous pouvez le voir visuellement. C'est aussi beaucoup plus d'opérations par boucle que vous n'en obtenez for i in $(seq 1 1000000). Et cela peut ne pas être évident pour vous, c'est pourquoi faire des tests comme celui-ci est précieux.

Démos

# show that seq is fast
$ time (seq 1 1000000 | wc)
 1000000 1000000 6888894

real    0m0.227s
user    0m0.239s
sys     0m0.008s

# show that {..} is fast
$ time (echo {1..1000000} | wc)
       1 1000000 6888896

real    0m1.778s
user    0m1.735s
sys     0m0.072s

# Show that for loops (even with a : noop) are slow
$ time (for i in {1..1000000} ; do :; done | wc)
       0       0       0

real    0m3.642s
user    0m3.582s
sys 0m0.057s

# show that echo is slow
$ time (for i in {1..1000000} ; do echo $i; done | wc)
 1000000 1000000 6888896

real    0m7.480s
user    0m6.803s
sys     0m2.580s

$ time (for i in $(seq 1 1000000) ; do echo $i; done | wc)
 1000000 1000000 6888894

real    0m7.029s
user    0m6.335s
sys     0m2.666s

# show that C-style for loops are slower
$ time (for (( i=1; i<=1000000; i++ )) ; do echo $i; done | wc)
 1000000 1000000 6888896

real    0m12.391s
user    0m11.069s
sys     0m3.437s

# show that arithmetic expansion is even slower
$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $i; i=$(($i+1)); done | wc)
 1000000 1000000 6888896

real    0m19.696s
user    0m18.017s
sys     0m3.806s

$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $i; ((i=i+1)); done | wc)
 1000000 1000000 6888896

real    0m18.629s
user    0m16.843s
sys     0m3.936s

$ time (i=1; e=1000000; while [ $i -le $e ]; do echo $((i++)); done | wc)
 1000000 1000000 6888896

real    0m17.012s
user    0m15.319s
sys     0m3.906s

# even a noop is slow
$ time (i=1; e=1000000; while [ $((i++)) -le $e ]; do :; done | wc)
       0       0       0

real    0m12.679s
user    0m11.658s
sys 0m1.004s

1
Agréable! Je ne suis cependant pas d'accord avec votre résumé. Il me semble que $(seq)c'est à peu près la même vitesse que {a..b}. De plus, chaque opération prend environ le même temps, ajoute donc environ 4 μs à chaque itération de la boucle pour moi. Ici, une opération est un écho dans le corps, une comparaison arithmétique, un incrément, etc. Est-ce surprenant? Peu importe combien de temps il faut à l'attirail de la boucle pour faire son travail - le temps d'exécution sera probablement dominé par le contenu de la boucle.
bobbogo

@bobbogo vous avez raison, il s'agit vraiment du nombre d'opérations. J'ai mis à jour ma réponse pour refléter cela. De nombreux appels que nous faisons effectuent en réalité plus d'opérations que nous ne le pensons. J'ai réduit cela à partir d'une liste d'environ 50 tests que j'ai effectués. Je m'attendais à ce que mes recherches soient trop ringardes même pour cette foule. Comme toujours, je suggère de prioriser vos efforts de codage comme suit: raccourcissez-le; Rendez-le lisible; Fais le plus rapidement; Rendez-le portable. Souvent, # 1 provoque # 3. Ne perdez pas votre temps sur # 4 jusqu'à ce que vous le deviez.
Bruno Bronosky

8

Je sais que cette question concerne bash, mais - pour mémoire - ksh93est plus intelligente et la met en œuvre comme prévu:

$ ksh -c 'i=5; for x in {1..$i}; do echo "$x"; done'
1
2
3
4
5
$ ksh -c 'echo $KSH_VERSION'
Version JM 93u+ 2012-02-29

$ bash -c 'i=5; for x in {1..$i}; do echo "$x"; done'
{1..5}

8

C'est une autre façon:

end=5
for i in $(bash -c "echo {1..${end}}"); do echo $i; done

1
Cela a pour frais généraux de générer un autre obus.
codeforester

1
En fait, c'est très terrible car il fait apparaître 2 obus quand 1 suffirait.
Bruno Bronosky

8

Si vous voulez rester aussi proche que possible de la syntaxe des accolades, essayez la rangefonction de bash-tricks 'range.bash .

Par exemple, tous les éléments suivants feront exactement la même chose que echo {1..10} :

source range.bash
one=1
ten=10

range {$one..$ten}
range $one $ten
range {1..$ten}
range {1..10}

Il essaie de prendre en charge la syntaxe bash native avec le moins de "gotchas" possible: non seulement les variables sont prises en charge, mais le comportement souvent indésirable des plages non valides fournies sous forme de chaînes (par exemple for i in {1..a}; do echo $i; done) est également empêché.

Les autres réponses fonctionneront dans la plupart des cas, mais elles présentent toutes au moins l'un des inconvénients suivants:

  • Beaucoup d'entre eux utilisent des sous - coquilles , ce qui peut nuire aux performances et peut ne pas être possible sur certains systèmes.
  • Beaucoup d'entre eux dépendent de programmes externes. Mêmeseq est un binaire qui doit être installé pour être utilisé, doit être chargé par bash, et doit contenir le programme que vous attendez, pour qu'il fonctionne dans ce cas. Omniprésent ou non, c'est beaucoup plus sur lequel s'appuyer que le langage Bash lui-même.
  • Les solutions qui n'utilisent que la fonctionnalité native de Bash, comme @ ephemient, ne fonctionneront pas sur les plages alphabétiques, comme {a..z}; l'expansion de l'accolade sera. La question portait sur les gammes de nombres , cependant, c'est donc un problème.
  • La plupart d'entre eux ne sont pas visuellement similaires à la {1..10} syntaxe de la plage étendue accolades, donc les programmes qui utilisent les deux peuvent être un peu plus difficiles à lire.
  • La réponse de @ bobbogo utilise une partie de la syntaxe familière, mais fait quelque chose d'inattendu si la $ENDvariable n'est pas un "serre-livre" de plage valide pour l'autre côté de la plage. Si END=a, par exemple, une erreur ne se produit pas et la valeur textuelle{1..a} est répercutée. Il s'agit également du comportement par défaut de Bash - il est souvent inattendu.

Avertissement: je suis l'auteur du code lié.


7

Remplacez {}par (( )):

tmpstart=0;
tmpend=4;

for (( i=$tmpstart; i<=$tmpend; i++ )) ; do 
echo $i ;
done

Rendements:

0
1
2
3
4

J'ai inclus cette réponse dans ma réponse de comparaison des performances ci-dessous. stackoverflow.com/a/54770805/117471 (Ceci est une note pour moi de garder une trace de ceux qu'il me reste à faire.)
Bruno Bronosky

6

Ce sont tous bien, mais seq est censé être obsolète et la plupart ne fonctionnent qu'avec des plages numériques.

Si vous placez votre boucle for entre guillemets doubles, les variables de début et de fin seront déréférencées lorsque vous faites écho à la chaîne, et vous pouvez renvoyer la chaîne directement à BASH pour exécution. $idoit être échappé avec \ pour qu'il ne soit PAS évalué avant d'être envoyé au sous-shell.

RANGE_START=a
RANGE_END=z
echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash

Cette sortie peut également être affectée à une variable:

VAR=`echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash`

La seule "surcharge" que cela devrait générer devrait être la deuxième instance de bash, donc elle devrait convenir aux opérations intensives.


5

Si vous faites des commandes shell et que vous (comme moi) avez un fétiche pour le pipelining, celui-ci est bon:

seq 1 $END | xargs -I {} echo {}


3

Il existe de nombreuses façons de le faire, mais celles que je préfère sont indiquées ci-dessous

En utilisant seq

Synopsis de man seq

$ seq [-w] [-f format] [-s string] [-t string] [first [incr]] last

Syntaxe

Commande complète
seq first incr last

  • le premier est le numéro de départ dans la séquence [est facultatif, par défaut: 1]
  • incr est incrément [est facultatif, par défaut: 1]
  • dernier est le dernier numéro de la séquence

Exemple:

$ seq 1 2 10
1 3 5 7 9

Uniquement avec le premier et le dernier:

$ seq 1 5
1 2 3 4 5

Seulement avec dernier:

$ seq 5
1 2 3 4 5

En utilisant {first..last..incr}

Ici premier et dernier sont obligatoires et incr est facultatif

Utiliser juste le premier et le dernier

$ echo {1..5}
1 2 3 4 5

Utilisation de incr

$ echo {1..10..2}
1 3 5 7 9

Vous pouvez l'utiliser même pour les personnages comme ci-dessous

$ echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z

3

si vous ne voulez pas utiliser ' seq' ou ' eval' ou jotou le format d'expansion arithmétique par exemple. for ((i=1;i<=END;i++)), ou d'autres boucles, par exemple. while, et vous ne voulez pas ' printf' et heureux ' echo' seulement, alors cette solution de contournement simple pourrait correspondre à votre budget:

a=1; b=5; d='for i in {'$a'..'$b'}; do echo -n "$i"; done;' echo "$d" | bash

PS: Mon bash n'a pas seqde commande ' ' de toute façon.

Testé sur Mac OSX 10.6.8, Bash 3.2.48


0

Cela fonctionne dans Bash et Korn, peut également passer d'un nombre supérieur à un nombre inférieur. Probablement pas plus rapide ou plus joli mais fonctionne assez bien. Gère également les négatifs.

function num_range {
   # Return a range of whole numbers from beginning value to ending value.
   # >>> num_range start end
   # start: Whole number to start with.
   # end: Whole number to end with.
   typeset s e v
   s=${1}
   e=${2}
   if (( ${e} >= ${s} )); then
      v=${s}
      while (( ${v} <= ${e} )); do
         echo ${v}
         ((v=v+1))
      done
   elif (( ${e} < ${s} )); then
      v=${s}
      while (( ${v} >= ${e} )); do
         echo ${v}
         ((v=v-1))
      done
   fi
}

function test_num_range {
   num_range 1 3 | egrep "1|2|3" | assert_lc 3
   num_range 1 3 | head -1 | assert_eq 1
   num_range -1 1 | head -1 | assert_eq "-1"
   num_range 3 1 | egrep "1|2|3" | assert_lc 3
   num_range 3 1 | head -1 | assert_eq 3
   num_range 1 -1 | tail -1 | assert_eq "-1"
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.