Bash Range: Sequence Expression Syntax and Examples

The Bash sequence expression generates a range of integers or characters by defining a start and end point. It is most commonly used in for
loops to iterate over a numeric or alphabetic range without writing out each value manually.
This guide covers the sequence expression syntax, step increments, zero-padding, character ranges, practical loop examples, and how to work with dynamic ranges using variables.
Bash Sequence Expression Syntax
The sequence expression takes the following form:
{START..END[..INCREMENT]}- The expression begins with an opening brace and ends with a closing brace.
STARTandENDcan be either positive integers or single characters.- The
STARTandENDvalues are mandatory and separated with two dots.., with no space between them. - The
INCREMENTvalue is optional. If present, it must be separated from theENDvalue with two dots.., with no space between them. - The expression expands to each number or character between
STARTandEND, including the provided values. - An incorrectly formed expression is left unchanged.
Integer Ranges
Here is the expression in action — generating a range from 0 to 3:
echo {0..3}0 1 2 3If START is greater than END, the expression creates a decrementing range:
echo {3..0}3 2 1 0Character Ranges
The sequence expression also works with single characters. The following example prints the lowercase alphabet:
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 zWhen characters are given, the expression expands in lexicographic order. You can also use uppercase letters:
echo {A..Z}Increment and Step
When an INCREMENT is given, it sets the step between each generated value:
for i in {0..20..5}
do
echo "Number: $i"
doneNumber: 0
Number: 5
Number: 10
Number: 15
Number: 20You can use a negative increment to step down:
for i in {10..0..2}
do
echo "Number: $i"
doneNumber: 10
Number: 8
Number: 6
Number: 4
Number: 2
Number: 0Leading Zeros
When using integers, you can force each number to have the same width by prefixing START or END with a leading zero:
for i in {00..5}
do
echo "Number: $i"
doneNumber: 00
Number: 01
Number: 02
Number: 03
Number: 04
Number: 05Prefix and Suffix
The expression can be combined with static text before or after the braces:
echo file{01..4}.txtfile01.txt file02.txt file03.txt file04.txtThis is useful for generating file names, directory names, or any pattern that includes a numeric suffix.
Using Ranges in for Loops
The sequence expression is most commonly used in for loops. The following example iterates from 1 to 5 and prints each value:
If you are looking for the Bash equivalent of Python’s for i in range(...), brace expansion is the simplest option for fixed ranges.
for i in {1..5}
do
echo "Iteration: $i"
doneIteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5A common use case is creating a set of numbered directories:
for i in {1..5}
do
mkdir "backup_$i"
doneThis creates backup_1 through backup_5 in the current directory.
Variable Ranges with seq
A common point of confusion is that Bash does not expand variables inside brace expressions. If you try to use a variable as START or END, the brace expression is left unexpanded:
START=1
END=5
echo {$START..$END}{1..5}The literal string {1..5} is printed instead of the expanded range. This is a Bash limitation — brace expansion happens before variable substitution.
To use a dynamic range, use the seq command instead:
START=1
END=5
for i in $(seq $START $END)
do
echo "Number: $i"
doneNumber: 1
Number: 2
Number: 3
Number: 4
Number: 5seq also accepts a step argument:
for i in $(seq 0 2 10)
do
echo "Number: $i"
doneNumber: 0
Number: 2
Number: 4
Number: 6
Number: 8
Number: 10Another option for variable ranges is a C-style for loop, which supports variables directly:
START=1
END=5
for ((i=START; i<=END; i++))
do
echo "Number: $i"
doneBoth seq and the C-style loop work reliably with variables. Use whichever reads more clearly for your script.
Practical Examples
Countdown timer
for i in {10..1}
do
echo "$i..."
sleep 1
done
echo "Done"Generate test files
for i in {1..10}
do
touch "testfile_${i}.log"
donePrint columns of the alphabet
for c in {a..z}
do
printf "%s " "$c"
done
echoCreate numbered backups
for i in {01..07}
do
cp config.conf "config_backup_${i}.conf"
doneQuick Reference
| Expression | Result |
|---|---|
{1..5} | 1 2 3 4 5 |
{5..1} | 5 4 3 2 1 |
{0..10..2} | 0 2 4 6 8 10 |
{01..04} | 01 02 03 04 (zero-padded) |
{a..e} | a b c d e |
{A..E} | A B C D E |
file{1..3}.txt | file1.txt file2.txt file3.txt |
seq $START $END | Dynamic integer range using variables |
seq $START $STEP $END | Dynamic range with step |
FAQ
Why does {$START..$END} not work?
Brace expansion in Bash happens before variable substitution, so {$START..$END} is treated as a literal string rather than a range. Use seq $START $END inside a command substitution, or use a C-style for ((i=START; i<=END; i++)) loop instead.
What is the difference between {1..5} and seq 1 5?{1..5} is a pure Bash brace expansion — fast and with no external command. seq 1 5 is an external command that prints numbers to standard output, one per line. The main practical difference is that brace expansion does not support variables, while seq does.
Can I use the sequence expression with strings longer than one character?
No. The sequence expression only supports single characters or integers. For multi-character strings you need a different approach, such as an array or a loop over a list.
How do I create a reverse or countdown range?
Set START higher than END: {5..1}. With an increment, use {10..0..2} to step down by 2.
Can I use the sequence expression outside of for loops?
Yes. echo {1..5} prints the expanded values space-separated on a single line. You can also use it in command arguments, file globs, or anywhere Bash performs brace expansion — for example mkdir dir{1..5} creates five directories at once.
Conclusion
Use {START..END} for fixed ranges in loops and brace expansions. When you need a dynamic range driven by variables, reach for seq $START $END or a C-style for ((i=START; i<=END; i++)) loop. For more on Bash loops, see the Bash for loop guide
.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page