Celeb Glow
updates | March 28, 2026

Run through two sequences in one loop

I'm trying to run through two sequences in the same loop in my shell like below:

#!/bin/bash
for i in (1..15) and (20..25) ;
do echo $i ...... .....other process
done

any idea how I can achieve this?

3

4 Answers

You only need brace expansion for that

$ for n in {1..3} {200..203}; do echo $n; done
1
2
3
200
201
202
203

We can pass a list to for (for i in x y z; do stuff "$i"; done).

So here, braces { } get the shell to expand your sequences into a list. You only need put a space between them, since the shell splits lists of arguments on those.

3

Alternatively we can use seq (print a sequence of numbers), here are two equivalent examples:

for i in `seq 1 3` `seq 101 103`; do echo $i; done
for i in $(seq 1 3) $(seq 101 103); do echo $i; done

If it is a script, for repetitive tasks, you can use functions:

#!/bin/bash
my_function() { echo "$1"; }
for i in {1..3}; do my_function "$i"; done
for i in {101..103}; do my_function "$i"; done
#!/bin/bash
my_function() { for i in `seq $1 $2`; do echo "$i"; done; }
my_function "1" "3"
my_function "101" "103"

Zanna's answer and pa4080's answer are both good and I'd probably go with one of them in most circumstances. Perhaps it goes without saying, but for the sake of completeness, I'll say it anyway: You can load each value into an array and then loop over the array. For example:

the_array=( 1 2 3 4 5 6 7 8 9 10 20 21 22 23 24 25 )
for i in "${the_array[@]}";
do echo $i
done
2

Looping without a loop

Zanna's answer is absolutely correct and well suited for bash, but we can improve that even more without utilizing a loop.

printf "%d\n" {1..15} {20..25}

Behavior of printf is such that if the number of ARGUMENTS is greater than format controls in 'FORMAT STRING', then printf will split all ARGUMENTS into equal chunks and keep fitting them to the format string over and over until it runs out of ARGUMENTS list.

If we're striving for portability, we can utilize printf "%d\n" $(seq 1 15) $(seq 20 25) instead

Let's take this further and more fun. Say we want to perform an action rather than just printing numbers. For creating files out of that sequence of numbers, we could easily do touch {1..15}.txt {20..25}.txt. What if we want multiple things to occur? We could also do something like this:

$ printf "%d\n" {1..15} {20..25} | xargs -I % bash -c 'touch "$1.txt"; stat "$1.txt"' sh %

Or if we want to make it old-school style:

printf "%d\n" {1..15} {20..25} | while read -r line; do touch "$line".txt; stat "$line".txt; rm "$line".txt;
done

Portable but verbose alternative

If we want to make a script solution that works with shells that don't have brace expansion ( which is what {1..15} {20..25} relies on) , we can write a simple while loop:

#!/bin/sh
start=$1
jump=$2
new_start=$3
end=$4
i=$start
while [ $i -le $jump ]
do printf "%d\n" "$i" i=$((i+1)) if [ $i -eq $jump ] && ! [ $i -eq $end ];then printf "%d\n" "$i" i=$new_start jump=$end fi
done

Of course this solution is more verbose, some things could be shortened, but it works. Tested with ksh, dash, mksh, and of course bash.


Bash C-style loop

But if we wanted to make a loop bash-specific ( for whatever reason, perhaps not just printing but also doing something with those numbers ), we can also do this (basically C-loop version of the portable solution) :

last=15; for (( i=1; i<=last;i++ )); do printf "%d\n" "$i"; [[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;} ;done

Or in more readable format:

last=15
for (( i=1; i<=last;i++ ));
do printf "%d\n" "$i" [[ $i -eq $last ]] && ! [[ $i -eq 25 ]] && { i=19;last=25;}
done

Performance comparison of different looping approaches

bash-4.3$ time bash -c 'printf "%d\n" {0..50000}>/dev/null'
real 0m0.196s
user 0m0.124s
sys 0m0.028s
bash-4.3$ time bash -c 'for i in {1..50000}; do echo $i > /dev/null; done'
real 0m1.819s
user 0m1.328s
sys 0m0.476s
bash-4.3$ time bash -c ' i=0;while [ $i -le 50000 ]; do echo $i>/dev/null; i=$((i+1)); done'
real 0m3.069s
user 0m2.544s
sys 0m0.500s
bash-4.3$ time bash -c 'for i in $(seq 1 50000); do printf "%d\n" > /dev/null; done'
real 0m1.879s
user 0m1.344s
sys 0m0.520s

Non-shell alternative

Just because we can here's Python solution

$ python3 -c 'print("\n".join([str(i) for i in (*range(1,16),*range(20,26))]))'

Or with a bit of shell:

bash-4.3$ python3 << EOF
> for i in (*range(16),*range(20,26)):
> print(i)
> EOF
2

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy