Generate Number Sequences with GNU seq
Learn GNU seq properly and you will never again write a five-line loop just to count from 1 to 10. This guide covers ranges, descending counts, padded output and custom separators, using coreutils 9.4 (package version 9.4-3ubuntu6.3). Allow about ten minutes; you need only a shell and an ordinary user account, no elevated privileges.
The route
Jump straight to the step you need, or tick off Done means at the end.
seq writes to standard output, which makes it brilliant in pipelines and shell loops but also means a careless redirection can overwrite a file. Keep the destination explicit and check what you generated before feeding it to another command.
1. Check the installed command
Confirm which executable your shell will run and note its version. Both checks are read-only:
$ command -v seq
/usr/bin/seq
$ seq --version | head -n 1
seq (GNU coreutils) 9.4
The local manual page is dated August 2026 and describes three operand forms: LAST, FIRST LAST, and FIRST INCREMENT LAST. Every numeric operand is treated as a floating-point value, even when it looks like an integer.
Checkpoint
If command -v seq points somewhere unexpected, stop and check your PATH before comparing results with this guide.
2. Generate the basic range
One operand: seq starts at 1 and counts by 1 up to the value you gave it.
$ seq 5
1
2
3
4
5
Two operands: the first becomes the starting value.
$ seq 3 7
3
4
5
6
7
The default separator is a newline, and output ends with one too, which is exactly what line-oriented tools like while read, grep or xargs want.
3. Choose the increment explicitly
Use three operands when the step matters. A negative increment gives you a descending range:
$ seq 5 -2 1
5
3
1
- seq will not infer a negative step for you. An omitted increment is always 1, even when the first value is bigger than the last, so
seq 5 1produces no output and still exits successfully. This is the trap that catches people: no error, just silence. Make the direction explicit in scripts. - The sequence stops before it overshoots. It does not force the last operand into the output.
seq 1 2 4prints 1 and 3, because the next value, 5, is beyond 4.
Checkpoint
Verify the shape before trusting a range inside a loop:
$ test "$(seq 5 -2 1)" = "5
3
1" && echo "range is correct"
range is correct
4. Control separators and padding
-s or --separator places a string between values; the whole output still ends with a newline:
$ seq -s ', ' 1 3
1, 2, 3
Use -w or --equal-width for fixed-width decimal output, padded with leading zeroes:
$ seq -w 8 10
08
09
10
For a label or a different numeric presentation, use the printf-style format option. The format needs a suitable floating-point conversion:
$ seq -f 'item-%02g' 1 3
item-01
item-02
item-03
Tip
Quote the format and separator in scripts. An unquoted space, wildcard or shell metacharacter gets interpreted by the shell before seq ever sees it.
5. Pipe it instead of building a giant argument list
For line-oriented processing, pipe straight into the next program:
$ seq 1 5 | while IFS= read -r number; do
> printf 'number=%s
' "$number"
> done
number=1
number=2
number=3
number=4
number=5
This keeps each value on its own line and avoids command substitution. $(seq 1 5) strips trailing newlines and then subjects the result to word splitting when used unquoted; fine for a small trusted list, a bad default for anything with spaces or for ranges long enough to stress an argument list.
If a downstream command wants arguments rather than lines, use xargs carefully and test the edge cases first. For very long sequences, streaming is easier to reason about than expanding the whole thing into one invocation.
6. Treat floating-point ranges as approximate
GNU seq accepts decimal and scientific notation, inferring the output format when you skip -f:
$ seq 0.5 0.25 1
0.50
0.75
1.00
The arithmetic is floating-point, full stop. Very small increments, very large integers and values near a representation boundary can repeat, skip or round unexpectedly. If exact values matter, work in integers and convert at the boundary, or reach for a tool built for exact decimal or arbitrary-precision arithmetic.
Warning
There is no useful infinite-loop protection. seq inf is documented upstream as an infinite sequence. Do not run an unbounded sequence in a terminal, service or unattended job unless you deliberately have a separate stop condition. Press Ctrl+C to stop a foreground test; a background one needs finding and killing the normal way.
7. Handle errors and file output safely
The increment must not be zero, and operands must not be NaN. A bad range is never a reason to reach for sudo:
$ seq 1 0 3
seq reports an invalid zero increment
$ printf 'exit status: %s
' "$?"
exit status: 1
The exact diagnostic text can vary by locale, but a non-zero exit status always means failure. Check it immediately if a pipeline must not continue after a bad range, and do not assume the final command's status describes everything that ran before it.
Warning
Shell redirection with > truncates an existing destination before seq even runs. For a new file, pick a new name and verify it:
$ seq -w 1 3 > numbers.txt
$ test -s numbers.txt && cat numbers.txt
01
02
03
For a file that already matters, write to a temporary file in the same directory, inspect it, then swap it in only once you are satisfied. A failed command can leave the redirected file empty or partial, and there is no recovery for an old file that has already been truncated unless you have a backup.
Done means
- Confirmed the version of GNU
seqactually installed. - Used an explicit negative increment for any descending range.
- Picked
-s,-wor-ffor the output shape you actually need. - Accounted for floating-point approximation before trusting decimal or very large ranges.
- Checked exit status and protected important files from accidental truncation.