Making lists with jot and seq
September 2, 2019 at 10:12 AM by Dr. Drang
The Mac comes with two command-line tools for making sequential lists: jot
and seq
. In the past, I’ve tended to use jot
, mainly because that’s the one I learned first. But seq
can do almost everything jot
can, and its argument ordering makes more sense in many situations.
The point of both commands is to generate a list of strings that include sequential numbers.1 At their most basic, jot
and seq
each produce a set of lines with numbers that count up from one. Both
jot 5
and
seq 5
produce the same output:
1
2
3
4
5
More interesting results come from adding arguments and options.
Arguments
jot
can take up to four arguments; seq
up to three. Here’s a table of how the arguments are ordered.
Arguments | jot |
seq |
---|---|---|
1 | count | last |
2 | count first | first last |
3 | count first last | first step last |
4 | count first last step |
As you can see, additional arguments get added to the end for jot
but are inserted for seq
. As we’ve seen above, for the one-argument case, jot
’s count and seq
’s last are effectively the same, because both commands have default starting points and step sizes of 1.2
For the two-argument case, both commands keep the default step size as 1 but allow you to change the starting point. To generate numbers from 5 through 10, you’d use either
jot 6 5
or
seq 5 10
To me, the seq
arguments are easier to remember and a more natural expression of what’s intended. It’s easy to make an off-by-one error and try
jot 5 5
which will get you only up to 9.
As far as I’m concerned, jot
with three arguments is worthless. If I know the starting and stopping points, and the step size is still at its default of one, the count parameter is redundant. You can avoid doing the subtraction in your head (and then remembering to add 1 to avoid the off-by-one error) by filling the count slot with a hyphen:
jot - 5 10
This is fine, but seq 5 10
is simpler.
The three-argument seq
and the four-argument jot
allow you to specify the step size. Again, jot
’s count is redundant and it’s best to put a hyphen in its place to allow the computer to do the arithmetic. To get from 10 to 40 counting by 5s, enter
jot - 10 40 5
to get
10
15
20
25
30
35
40
The seq
command to get the same result is
seq 10 5 40
This is the one place where I find seq
’s arguments hard to remember. So many programming languages use the order first, last, step that my fingers do that before I can stop them. There’s nothing illogical about the first, step, last ordering, but it’s not what I’m used to.
Options
Just printing out lines with numbers is dull. The real value of jot
and seq
comes from applying options (often called switches) that allow us to format the numbers and include them in other text. Here are the options for jot
and seq
:
Option | jot |
seq |
---|---|---|
output format | -w string |
-f string |
repeated string | -b string |
|
equal width | -w |
|
separator | -s string |
-s string |
omit final newline | -n |
|
precision | -p decimals |
|
characters | -c |
|
random | -r |
The option I use most often is -w
for jot
and the nearly equivalent -f
for seq
. In both cases, the string argument is a printf
-style formatting string. So if I wanted to generate a bunch of sequential file names, I could use
jot -w "file%02d.txt" 5
or
seq -f "file%02.0f.txt" 5
to get3
file01.txt
file02.txt
file03.txt
file04.txt
file05.txt
Here’s a situation where jot
is a little more sensible. Even though both commands treat the numbers they generate as floating point, jot
recognizes when the numbers have no decimal part and allows you to use the %d
format specifier. seq
forces you to use a floating point specifier, like %f
or %e
, which then forces you to explicitly state that the number of digits after the decimal point is 0. If you don’t, you’ll get a mess. For example,
seq -f "file%02f.txt" 5
returns
file1.000000.txt
file2.000000.txt
file3.000000.txt
file4.000000.txt
file5.000000.txt
The -b
option for jot
will repeat the given string as many times as specified. The string isn’t a formatting string and won’t include the numbers generated by jot
.
jot -b Hello 4
returns
Hello
Hello
Hello
Hello
which I guess could be useful. You might think you could use the -w
option with a string that doesn’t include a formatting specifier. But if you try that, jot
will add the number to the end anyway.
jot -w Hello 4
returns
Hello1
Hello2
Hello3
Hello4
which is kind of presumptuous of it.
seq
is better behaved.
seq -f Hello 4
returns
Hello
Hello
Hello
Hello
just as you’d expect.
By the way, if you want just a list of numbers, but you want them zero-padded to be of the same character length, seq
has you covered:
seq -w 8 12
returns
08
09
10
11
12
You could achieve the same thing with a formatting string, but the -w
option is a little shorter.
We’ve been looking at output where each item in the sequence is on its own line—i.e., separated by newlines—but both commands have an -s
option for specifying another separator. The option works a little differently for the two commands.
jot -s, 5 8
gives
8,9,10,11,12
whereas
seq -s, 8 12
gives
8,9,10,11,12,
You see that seq
’s “separator” (that’s what it’s called in the man page) is really a suffix. To get the same output as jot
, you can pipe the output through sed
to delete the last character:
seq -s, 8 12 | sed 's/.$//'
Kind of annoying.
One advantage seq
has over jot
with regard to separators is that it understands tabs.
seq -s "\t" 8 12 | sed 's/.$//'
will give you the numbers separated by tab characters. But jot
treats the backslashed t literally.
jot -s "\t" 5 8
will give you
8\t9\t10\t11\t12
Not helpful.
One more thing related to -s
. Because jot
treats the separator as an actual separator, the newline that’s added by default to the end of the output isn’t handled by -s
. If you don’t want jot
to add it, including the -n
option will omit it. This is just like the -n
option to echo
.
As mentioned above, both commands handle floating point numbers, but they have different defaults.
seq -w 7 .5 9
returns
7.0
7.5
8.0
8.5
9.0
as you would expect. But the similar
jot - 7 9 .5
returns
7
8
8
8
9
which seems bizarre. The trick is that jot
has a default precision of zero decimal places, so it’s rounding to the nearest integer. The default precision can be changed with the -p
option.
jot -p1 - 7 9 .5
returns
7.0
7.5
8.0
8.5
9.0
which is almost certainly what you wanted.
Finally, I want to talk about one clear advantage that jot
has over seq
: the ability to generate sequences of characters using the -c
option.
jot -c 5 65
returns
A
B
C
D
E
What it’s doing is interpreting each number as an ASCII code and returning its corresponding character. Even better, you can use character arguments:
jot -c - a e
returns
a
b
c
d
e
You can get the same effect by using the %c
formatting specifier in the -w
option. I’ve used this feature of jot
to generate apartment addresses when working with a building that uses letters for its units. For example, say I am dealing with a five-story building in which the apartments start on the second floor and are given the letters A through D. I want to quickly generate a list of all the apartment addresses. The command is
for n in `seq 2 5`; do jot -w "Apt. $n%c" - A D; done
and the output is
Apt. 2A
Apt. 2B
Apt. 2C
Apt. 2D
Apt. 3A
Apt. 3B
Apt. 3C
Apt. 3D
Apt. 4A
Apt. 4B
Apt. 4C
Apt. 4D
Apt. 5A
Apt. 5B
Apt. 5C
Apt. 5D
As a practical matter, with only 16 apartments, I probably wouldn’t bother with seq
or jot
. It’s faster to just type out the apartment addresses when the number is small. But with larger buildings, a command like this saves a lot of time and insures that I don’t skip or duplicate addresses. As with any automation, accuracy is as important as the time saved.
-
jot
also has an option for generating random numbers, but I’ve never had any use for that. ↩ -
That the counts start at 1 instead of 0 is an indication that these commands were written for normal humans, not programmers. ↩
-
The quotation marks aren’t necessary in either of these cases because the shell won’t process the formatting string before sending it to
jot
orseq
. But I have a hard time remembering which characters are special to the shell, so I tend to use quotation marks any time I have a string that includes potentially special characters like%
. ↩