Come posso scorrere su un intervallo di numeri definito dalle variabili in Bash?


1545

Come posso iterare su un intervallo di numeri in Bash quando l'intervallo è dato da una variabile?

So di poterlo fare (chiamato "espressione di sequenza" nella documentazione di Bash ):

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

Che dà:

1
2
3
4
5

Tuttavia, come posso sostituire uno dei due endpoint con una variabile? Questo non funziona:

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

Che stampa:

{1..5}


26
Ciao a tutti, le informazioni e i suggerimenti che ho letto qui sono tutti davvero utili. Penso che sia meglio evitare l'uso di seq. Il motivo è che alcuni script devono essere portatili e devono essere eseguiti su una vasta gamma di sistemi unix, in cui alcuni comandi potrebbero non essere presenti. Solo per fare un esempio, seq non è presente di default sui sistemi FreeBSD.


9
Non ricordo esattamente da quale versione di Bash, ma questo comando supporta anche gli zeri finali. Che a volte è davvero utile. Il comando for i in {01..10}; do echo $i; donedarebbe numeri come 01, 02, 03, ..., 10.
TOPR

1
Per quelli come me che vogliono solo scorrere l'ambito degli indici di un array , il modo bash sarebbe: myarray=('a' 'b' 'c'); for i in ${!myarray[@]}; do echo $i; done(notare il punto esclamativo). È più specifico della domanda originale, ma potrebbe aiutare. Vedi le espansioni dei parametri bash
PlasmaBinturong,

1
L'espansione della parentesi graffa viene utilizzata anche per espressioni come quelle {jpg,png,gif}che non sono direttamente affrontate qui, sebbene la risposta sia identica. Vedi Espansione del controvento con variabile? [duplicato] che è contrassegnato come duplicato di questo.
triplo

Risposte:


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

modifica: preferisco seqrispetto agli altri metodi perché posso davvero ricordarlo;)


36
seq comporta l'esecuzione di un comando esterno che di solito rallenta le cose. Questo potrebbe non avere importanza, ma diventa importante se stai scrivendo uno script per gestire molti dati.
paxdiablo,

37
Va bene per un one-liner. Anche la soluzione di Pax va bene, ma se le prestazioni fossero davvero un problema non userei uno script di shell.
eschercycle,

17
seq viene chiamato solo una volta per generare i numeri. exec () 'ing non dovrebbe essere significativo a meno che questo ciclo non sia all'interno di un altro circuito stretto.
Javier,

29
Il comando esterno non è davvero rilevante: se sei preoccupato per l'overhead dell'esecuzione di comandi esterni, non vuoi affatto usare gli script di shell, ma generalmente su unix l'overhead è basso. Tuttavia, esiste il problema dell'utilizzo della memoria se END è elevato.
Mark Baker,

18
Si noti che seq $ENDsarebbe sufficiente, poiché il valore predefinito deve iniziare da 1. Da man seq: "Se si omette FIRST o INCREMENT, il valore predefinito è 1".
fedorqui "SO smettere di danneggiare" il

475

Il seqmetodo è il più semplice, ma Bash ha una valutazione aritmetica integrata.

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

Il for ((expr1;expr2;expr3));costrutto funziona proprio come for (expr1;expr2;expr3)in C e in linguaggi simili e, come in altri ((expr))casi, Bash li considera aritmetici.


68
In questo modo si evita il sovraccarico di memoria di un elenco di grandi dimensioni e una dipendenza seq. Usalo!
bobbogo,

3
@MarinSagovac Questo fa il lavoro e non ci sono errori di sintassi. Sei sicuro che la tua shell sia Bash?
gniourf_gniourf,

3
@MarinSagovac Assicurati di creare #!/bin/bashla prima riga del tuo script. wiki.ubuntu.com/…
Melebius

7
solo una domanda molto breve al riguardo: why ((i = 1; i <= END; i ++)) AND NOT ((i = 1; i <= $ END; i ++)); perché non $ prima di END?
Baedsch,

5
@Baedsch: per lo stesso motivo non sono usato come $ i. bash man page afferma per la valutazione aritmetica: "All'interno di un'espressione, le variabili shell possono anche essere referenziate per nome senza usare la sintassi di espansione dei parametri."
user3188140

193

discussione

L'uso seqva bene, come ha suggerito Jiaaro. Pax Diablo ha suggerito un loop Bash per evitare di chiamare un sottoprocesso, con l'ulteriore vantaggio di essere più amico della memoria se $ END è troppo grande. Zathrus ha individuato un tipico bug nell'implementazione del ciclo e ha anche suggerito che, poiché si itratta di una variabile di testo, le conversioni continue avanti e indietro vengono eseguite con un rallentamento associato.

aritmetica intera

Questa è una versione migliorata del loop Bash:

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

Se l'unica cosa che vogliamo è la echo, allora potremmo scrivereecho $((i++)) .

effimero mi ha insegnato qualcosa: Bash permette for ((expr;expr;expr))costrutti. Da quando non ho mai letto l'intera pagina man di Bash (come ho fatto con la shell Korn (ksh pagina man della ), e molto tempo fa), mi mancava.

Così,

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

sembra essere il modo più efficiente in termini di memoria (non sarà necessario allocare memoria per consumare seq l'output, il che potrebbe essere un problema se END è molto grande), anche se probabilmente non è il "più veloce".

la domanda iniziale

eschercycle ha notato che la notazione { a .. b } Bash funziona solo con valori letterali; vero, secondo il manuale di Bash. Si può superare questo ostacolo con un singolo (interno) fork()senza un exec()(come nel caso della chiamata seq, che essendo un'altra immagine richiede un fork + exec):

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

Entrambi evale echosono built-in di Bash, ma fork()è necessario per la sostituzione del comando (il $(…)costrutto).


1
L'unico inconveniente del ciclo di stile C che non è possibile utilizzare gli argomenti della riga di comando, poiché iniziano con "$".
Karatedog

3
@karatedog: for ((i=$1;i<=$2;++i)); do echo $i; donein uno script funziona bene su bash v.4.1.9, quindi non vedo alcun problema con gli argomenti della riga di comando. Intendi qualcos'altro?
Tzot

Sembra che la soluzione eval sia più veloce di quella costruita in C-like per: $ time for ((i = 1; i <= 100000; ++ i)); fare :; fatto vero 0m21.220s utente 0m19.763s sys 0m1.203s $ tempo per i in $ (eval echo "{1..100000}"); fare :; fatto; real 0m13.881s user 0m13.536s sys 0m0.152s
Marcin Zaluski

3
Sì, ma eval è malvagio ... @MarcinZaluski time for i in $(seq 100000); do :; doneè molto più veloce!
F. Hauri,

Le prestazioni devono essere specifiche della piattaforma poiché la versione eval è la più veloce sulla mia macchina.
Andrew Prock,

103

Ecco perché l'espressione originale non ha funzionato.

Da man bash :

L'espansione del controvento viene eseguita prima di qualsiasi altra espansione e nel risultato vengono preservati tutti i caratteri speciali di altre espansioni. È rigorosamente testuale. Bash non applica alcuna interpretazione sintattica al contesto dell'espansione o al testo tra parentesi graffe.

Quindi, l' espansione del controvento è qualcosa fatto all'inizio come un'operazione macro puramente testuale, prima dell'espansione dei parametri.

Le shell sono ibridi altamente ottimizzati tra processori macro e linguaggi di programmazione più formali. Al fine di ottimizzare i casi d'uso tipici, la lingua è resa piuttosto complessa e vengono accettate alcune limitazioni.

Raccomandazione

Vorrei suggerire di attenersi alle funzionalità di Posix 1 . Ciò significa utilizzare for i in <list>; do, se l'elenco è già noto, altrimenti, utilizzare whileo seq, come in:

#!/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 è una grande shell e la utilizzo in modo interattivo, ma non inserisco i bash-isme nei miei script. Gli script potrebbero aver bisogno di una shell più veloce, una più sicura, una più incorporata. Potrebbe essere necessario eseguirli su qualsiasi cosa sia installata come / bin / sh, e quindi ci sono tutti i soliti argomenti pro-standard. Ricordi shellshock, aka bashdoor?


13
Non ho il potere, ma lo sposterei un po 'in cima alla lista, soprattutto con l'osservazione dell'ombelico bash ma immediatamente dopo lo stile C per il ciclo e la valutazione aritmetica.
mateor

2
Un'implicazione è che l'espansione del controvento non risparmia molta memoria rispetto a seqgrandi intervalli. Ad esempio, echo {1..1000000} | wcrivela che l'eco produce 1 riga, un milione di parole e 6.888.896 byte. Provare seq 1 1000000 | wcproduce un milione di righe, un milione di parole e 6.888.896 byte ed è anche più di sette volte più veloce, come misurato dal timecomando.
George

Nota: avevo precedentemente menzionato il whilemetodo POSIX nella mia risposta: stackoverflow.com/a/31365662/895245 Ma sono contento che tu sia d'accordo :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Ho incluso questa risposta nella mia risposta di confronto delle prestazioni di seguito. stackoverflow.com/a/54770805/117471 (Questa è una nota per me per tenere traccia di quelli che mi sono rimasti da fare.)
Bruno Bronosky,

@mateor Ho pensato che lo stile C per il ciclo e la valutazione aritmetica fossero la stessa soluzione. Mi sto perdendo qualcosa?
Oscar Zhang

73

Il modo POSIX

Se ti interessa la portabilità, usa l' esempio dello standard POSIX :

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

Produzione:

2
3
4
5

Cose che non sono POSIX:


Ho appena ricevuto 4 voti positivi per questa risposta, il che è molto insolito. Se questo è stato pubblicato su un sito Web di aggregazione di link, per favore dammi un link, evviva.
Ciro Santilli 4 冠状 病 六四 事件 法轮功

La citazione si riferisce x, non l'intera espressione. $((x + 1))va bene.
Chepner,

Sebbene non sia portatile e differisca da GNU seq(BSD seqconsente di impostare una stringa di terminazione di sequenza con -t), FreeBSD e NetBSD hanno anche rispettivamente seqda 9.0 e 3.0.
Adrian Günter,

@CiroSantilli @chepner $((x+1))e $((x + 1))analizzare esattamente lo stesso, come quando il parser tokenizza x+1sarà suddiviso in 3 token: x, +e 1. xnon è un token numerico valido, ma è un token con nome variabile valido, ma x+non lo è, quindi la divisione. +è un token operatore aritmetico valido, ma +1non lo è, quindi il token viene nuovamente suddiviso lì. E così via.
Adrian Günter,

Ho incluso questa risposta nella mia risposta di confronto delle prestazioni di seguito. stackoverflow.com/a/54770805/117471 (Questa è una nota per me per tenere traccia di quelli che mi sono rimasti da fare.)
Bruno Bronosky,

35

Un altro livello di riferimento indiretto:

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

2
+1: Inoltre, eval 'for i in {1 ..' $ END '}; do ... 'eval sembra il modo naturale di risolvere questo problema.
William Pursell,

28

Puoi usare

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

seq comporta l'esecuzione di un comando esterno che di solito rallenta le cose.
paxdiablo,

9
Non comporta l'esecuzione di un comando esterno per ogni iterazione, una sola volta. Se il momento di avviare un comando esterno è un problema, stai usando la lingua sbagliata.
Mark Baker,

1
Quindi la nidificazione è l'unico caso in cui questo conta? Mi chiedevo se ci fosse una differenza di prestazioni o qualche effetto collaterale tecnico sconosciuto?
Sqeaky,

@Squeaky Questa è una domanda separata whichtis risposta qui: stackoverflow.com/questions/4708549/...
tripleee

Ho incluso questa risposta nella mia risposta di confronto delle prestazioni di seguito. stackoverflow.com/a/54770805/117471 (Questa è una nota per me per tenere traccia di quelli che mi sono rimasti da fare.)
Bruno Bronosky,

21

Se ti serve il prefisso di quanto potresti apprezzare

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

che produrrà

07
08
09
10
11
12

4
Non printf "%02d\n" $isarebbe più facile di printf "%2.0d\n" $i |sed "s/ /0/"?
zb226,

19

Se sei su BSD / OS X puoi usare jot invece di seq:

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

17

Funziona bene in bash:

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

6
echo $((i++))funziona e lo combina su una riga.
Bruno Bronosky,

1
Questo ha estensioni bash non necessarie. A POSIX versione: stackoverflow.com/a/31365662/895245
Ciro Santilli郝海东冠状病六四事件法轮功

1
@Ciro, dal momento che la domanda afferma specificamente bash e ha un tag bash, penso che probabilmente scoprirai che le 'estensioni' bash sono più che ok :-)
paxdiablo

@paxdiablo Non intendo dire che non è corretto, ma perché non essere portatile quando possiamo ;-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

In bash, possiamo semplicemente fare while [[ i++ -le "$END" ]]; doper fare l'incremento (post) del test
Aaron McDaid,

14

Ho combinato alcune idee qui e misurato le prestazioni.

TL; DR Takeaways:

  1. seqe {..}sono davvero veloci
  2. fore i whileloop sono lenti
  3. $( ) è lento
  4. for (( ; ; )) i loop sono più lenti
  5. $(( )) è ancora più lento
  6. Preoccuparsi per i numeri N in memoria (seq o {..}) è sciocco (almeno fino a 1 milione.)

Queste non sono conclusioni . Dovresti guardare il codice C dietro ognuno di questi per trarre delle conclusioni. Si tratta più di come tendiamo a utilizzare ciascuno di questi meccanismi per eseguire il looping del codice. La maggior parte delle singole operazioni sono abbastanza vicine da avere la stessa velocità che nella maggior parte dei casi non avrà importanza. Ma un meccanismo come for (( i=1; i<=1000000; i++ ))è molte operazioni come puoi vedere visivamente. Sono anche molte più operazioni per ciclo di quante ne riceviatefor i in $(seq 1 1000000) . E questo potrebbe non essere ovvio per te, motivo per cui fare test come questo è prezioso.

Demos

# 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
Bello! Non sono d'accordo con il tuo sommario però. Mi sembra che $(seq)abbia la stessa velocità di {a..b}. Inoltre, ogni operazione richiede circa lo stesso tempo, quindi aggiunge circa 4μs a ciascuna iterazione del loop per me. Qui un'operazione è un'eco nel corpo, un confronto aritmetico, un incremento, ecc. C'è qualcosa di sorprendente? A chi importa quanto tempo impiega l'armamentario del loop per fare il suo lavoro: è probabile che il runtime sia dominato dal contenuto del loop.
Bobbogo,

@bobbogo hai ragione, si tratta davvero di contare le operazioni. Ho aggiornato la mia risposta per riflettere questo. Molte chiamate che effettuiamo eseguono effettivamente più operazioni di quelle che potremmo aspettarci. L'ho ristretto da un elenco di circa 50 test eseguiti. Mi aspettavo che la mia ricerca fosse troppo nerd anche per questa folla. Come sempre, suggerisco di dare la priorità ai tuoi sforzi di codifica in questo modo: Renderlo più breve; Renderlo leggibile; Renderlo più veloce; Rendilo portatile. Spesso # 1 causa # 3. Non perdere tempo con il n. 4 fino a quando non è necessario.
Bruno Bronosky,

8

So che questa domanda riguarda bash, ma - solo per la cronaca - ksh93è più intelligente e la implementa come previsto:

$ 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

Questo è un altro modo:

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

1
Questo ha il sovraccarico di generare un'altra shell.
codeforester

1
In realtà, questo è extra terribile perché genera 2 conchiglie quando 1 sarebbe sufficiente.
Bruno Bronosky,

8

Se vuoi rimanere il più vicino possibile alla sintassi dell'espressione di parentesi graffa, prova la rangefunzione da bash-tricks 'range.bash .

Ad esempio, tutto quanto segue farà esattamente la stessa cosa di echo {1..10}:

source range.bash
one=1
ten=10

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

Cerca di supportare la sintassi bash nativa con il minor numero possibile di "gotcha": non solo sono supportate le variabili, ma il comportamento spesso indesiderabile di intervalli non validi viene fornito come stringhe (ad es. for i in {1..a}; do echo $i; done viene impedito anche il ).

Le altre risposte funzioneranno nella maggior parte dei casi, ma tutte presentano almeno uno dei seguenti inconvenienti:

  • Molti di loro usano le conchiglie , che possono danneggiare le prestazioni e potrebbero non essere possibili su alcuni sistemi.
  • Molti di loro si affidano a programmi esterni. Ancheseq è un binario che deve essere installato per essere utilizzato, deve essere caricato da bash e deve contenere il programma che ci si aspetta, affinché funzioni in questo caso. Ubiquo o no, è molto di più su cui contare oltre al linguaggio Bash stesso.
  • Le soluzioni che utilizzano solo funzionalità native di Bash, come quelle di @ephemient, non funzioneranno su intervalli alfabetici, come {a..z}; l'espansione del rinforzo sarà. La domanda riguardava gli intervalli di numeri , quindi, questo è un cavillo.
  • La maggior parte di essi non è visivamente simile alla {1..10}sintassi dell'intervallo ampliato con parentesi graffe, quindi i programmi che usano entrambi possono essere un po 'più difficili da leggere.
  • La risposta di @ bobbogo utilizza parte della sintassi familiare, ma fa qualcosa di inaspettato se la $ENDvariabile non è un intervallo "bookend" valido per l'altro lato dell'intervallo. Se END=a, ad esempio, non si verificherà un errore e {1..a}verrà ripetuto il valore alla lettera . Questo è anche il comportamento predefinito di Bash: è spesso inaspettato.

Disclaimer: sono l'autore del codice collegato.


7

Sostituisci {}con (( )):

tmpstart=0;
tmpend=4;

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

I rendimenti:

0
1
2
3
4

Ho incluso questa risposta nella mia risposta di confronto delle prestazioni di seguito. stackoverflow.com/a/54770805/117471 (Questa è una nota per me per tenere traccia di quelli che mi sono rimasti da fare.)
Bruno Bronosky,

6

Questi sono tutti belli ma seq è presumibilmente deprecato e la maggior parte funziona solo con intervalli numerici.

Se racchiudi il tuo ciclo for tra virgolette doppie, le variabili di inizio e fine verranno dereferenziate quando fai eco alla stringa e puoi spedire la stringa a BASH per l'esecuzione. $ideve essere sottoposto a escape con \ 's, quindi NON viene valutato prima di essere inviato alla subshell.

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

Questo output può anche essere assegnato a una variabile:

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

L'unico "overhead" che questo dovrebbe generare dovrebbe essere la seconda istanza di bash, quindi dovrebbe essere adatto per operazioni intensive.


5

Se stai eseguendo comandi shell e tu (come me) hai un feticcio per il pipelining, questo è buono:

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


3

Ci sono molti modi per farlo, tuttavia quelli che preferisco sono indicati di seguito

utilizzando seq

Sinossi di man seq

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

Sintassi

Comando completo
seq first incr last

  • il primo è il numero iniziale nella sequenza [è facoltativo, per impostazione predefinita: 1]
  • incr is increment [è facoltativo, per impostazione predefinita: 1]
  • last è l'ultimo numero nella sequenza

Esempio:

$ seq 1 2 10
1 3 5 7 9

Solo con il primo e l'ultimo:

$ seq 1 5
1 2 3 4 5

Solo con l'ultimo:

$ seq 5
1 2 3 4 5

utilizzando {first..last..incr}

Qui primo e ultimo sono obbligatori e incr è facoltativo

Usando solo il primo e l'ultimo

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

Utilizzando incr

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

Puoi usarlo anche per personaggi come di seguito

$ 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

se non si desidera utilizzare ' seq' o ' eval' o il jotformato di espansione aritmetica, ad es. for ((i=1;i<=END;i++))o altri loop, ad es. whilee non vuoi solo " printf" e felice di " echo", quindi questa semplice soluzione potrebbe adattarsi al tuo budget:

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

PS: Il mio bash non ha seqcomunque il comando ' '.

Testato su Mac OSX 10.6.8, Bash 3.2.48


0

Questo funziona in Bash e Korn, inoltre può andare da numeri più alti a più bassi. Probabilmente non è il più veloce o più bello ma funziona abbastanza bene. Gestisce anche i negativi.

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"
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.