Bash Range: Sequence Expression Syntax and Examples

By 

Updated on

6 min read

Bash Sequence Expression Range

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:

txt
{START..END[..INCREMENT]}
  • The expression begins with an opening brace and ends with a closing brace.
  • START and END can be either positive integers or single characters.
  • The START and END values are mandatory and separated with two dots .., with no space between them.
  • The INCREMENT value is optional. If present, it must be separated from the END value with two dots .., with no space between them.
  • The expression expands to each number or character between START and END, 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:

Terminal
echo {0..3}
output
0 1 2 3

If START is greater than END, the expression creates a decrementing range:

Terminal
echo {3..0}
output
3 2 1 0

Character Ranges

The sequence expression also works with single characters. The following example prints the lowercase alphabet:

Terminal
echo {a..z}
output
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

When characters are given, the expression expands in lexicographic order. You can also use uppercase letters:

Terminal
echo {A..Z}

Increment and Step

When an INCREMENT is given, it sets the step between each generated value:

Terminal
for i in {0..20..5}
do
  echo "Number: $i"
done
output
Number: 0
Number: 5
Number: 10
Number: 15
Number: 20

You can use a negative increment to step down:

Terminal
for i in {10..0..2}
do
  echo "Number: $i"
done
output
Number: 10
Number: 8
Number: 6
Number: 4
Number: 2
Number: 0

Leading Zeros

When using integers, you can force each number to have the same width by prefixing START or END with a leading zero:

Terminal
for i in {00..5}
do
  echo "Number: $i"
done
output
Number: 00
Number: 01
Number: 02
Number: 03
Number: 04
Number: 05

Prefix and Suffix

The expression can be combined with static text before or after the braces:

Terminal
echo file{01..4}.txt
output
file01.txt file02.txt file03.txt file04.txt

This 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.

Terminal
for i in {1..5}
do
  echo "Iteration: $i"
done
output
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5

A common use case is creating a set of numbered directories:

Terminal
for i in {1..5}
do
  mkdir "backup_$i"
done

This 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:

Terminal
START=1
END=5
echo {$START..$END}
output
{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:

Terminal
START=1
END=5
for i in $(seq $START $END)
do
  echo "Number: $i"
done
output
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

seq also accepts a step argument:

Terminal
for i in $(seq 0 2 10)
do
  echo "Number: $i"
done
output
Number: 0
Number: 2
Number: 4
Number: 6
Number: 8
Number: 10

Another option for variable ranges is a C-style for loop, which supports variables directly:

Terminal
START=1
END=5
for ((i=START; i<=END; i++))
do
  echo "Number: $i"
done

Both seq and the C-style loop work reliably with variables. Use whichever reads more clearly for your script.

Practical Examples

Countdown timer

Terminal
for i in {10..1}
do
  echo "$i..."
  sleep 1
done
echo "Done"

Generate test files

Terminal
for i in {1..10}
do
  touch "testfile_${i}.log"
done

Print columns of the alphabet

Terminal
for c in {a..z}
do
  printf "%s " "$c"
done
echo

Create numbered backups

Terminal
for i in {01..07}
do
  cp config.conf "config_backup_${i}.conf"
done

Quick Reference

ExpressionResult
{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}.txtfile1.txt file2.txt file3.txt
seq $START $ENDDynamic integer range using variables
seq $START $STEP $ENDDynamic 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

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