← back to latest

Count from 01 to 12 with the zeros already in place

seq -w 1 12

anatomy

seq
Print a sequence of numbers, one per line. It is an external program, not a shell feature, so its arguments can come from variables, command substitution, or arithmetic. Brace expansion cannot do that.
-w
Equal width. seq looks at the widest of the start and end values and pads every number with leading zeros to match. The width comes from the endpoints, not from a number you choose, so `seq -w 1 9` pads nothing at all.
1
The first number. With two arguments seq reads them as first and last. With three, the middle one is the step: `seq 0 15 60` counts in quarter hours.
12
The last number, and the one that sets the width here. Two digits wide, so 1 through 9 each get one zero. Change it to 100 and every line grows to three digits.

Sample output

$ seq -w 1 12
01
02
03
04
05
06
07
08
09
10
11
12

Twelve months, each two digits wide, ready to drop into a filename like report-2026-07.csv where a plain 7 would sort after 10 and break every glob that expects a fixed width.

When you would reach for it

Building month or day numbers for dated filenames, looping over numbered hosts like web01 through web12, or generating test fixtures that need to sort correctly with ls. It is also the answer when the upper bound lives in a variable: {1..$n} does not expand in bash because brace expansion runs before variable expansion, but seq -w 1 "$n" does what you meant.

Gotchas

  • When the first number is larger than the last, GNU seq on Debian prints nothing and exits 0, because the step still defaults to 1. The BSD seq on macOS counts down on its own. Pass the step explicitly, seq 12 -1 1, and both platforms agree.
  • The width comes from the endpoints, so a sequence that stays inside one digit gets no padding. seq -w 1 9 prints 1 to 9. For a fixed width regardless of range, use seq -f '%02g' 1 9, which always pads to two.
  • seq prints in %g format when it cannot tell the numbers are plain integers, and the macOS version does this sooner than GNU. seq 999999 1000001 can show 1e+06 on a Mac. Add -f '%.0f' when a script will handle large numbers on both systems.
  • Negative numbers count the minus sign toward the width. seq -w -5 5 prints -5 through -1, then 00, 01, and so on, because -5 is two characters wide.

Variants

$ seq -f 'web%02g' 1 12

A prefix and fixed-width padding in one format string. Prints web01 through web12. GNU and macOS; BusyBox on Alpine has no -f

$ echo report-2026-{01..12}.csv

Bash 4 and zsh. A leading zero on either bound tells brace expansion to pad every term to the wider bound, with no external program. Literal bounds only, no variables

$ seq -s+ 1 100 | bc

-s swaps the newline for any separator, so seq writes the expression 1+2+...+100 and bc adds it up. Prints 5050

lineage

seq first appeared in Version 8 Unix at Bell Labs in the mid-1980s and moved on to Plan 9, but it never made it into System V or the POSIX standard, which is why it still behaves a little differently depending on where you type it. The GNU version, written by Ulrich Drepper, arrived in the early 1990s as part of the shell utilities that later merged into coreutils. The BSDs went without one for years, writing `jot` instead, until NetBSD added its own seq and FreeBSD and macOS inherited it. Two independent rewrites of one unstandardized tool explain nearly every gotcha below.