nl

If the numbering options provided by cat isn't enough for you, nl might help you. Apart from options to customize the number formatting and the separator, you can also filter which lines should be numbered. Additionally, you can divide your input into sections and number them separately.

Default numbering

By default, nl will prefix line number and a tab character to every non-empty input lines. The default number formatting is 6 characters wide and right justified with spaces. Similar to cat, the nl command will concatenate multiple inputs.

# same as: cat -n greeting.txt fruits.txt nums.txt
$ nl greeting.txt fruits.txt nums.txt
     1  Hi there
     2  Have a nice day
     3  banana
     4  papaya
     5  mango
     6  3.14
     7  42
     8  1000

# example for input with empty lines, same as: cat -b
$ printf 'apple\n\nbanana\n\ncherry\n' | nl
     1  apple

     2  banana

     3  cherry

Number formatting

You can use the -n option to customize the number formatting. The available styles are:

  • rn right justified with space fillers (default)
  • rz right justified with leading zeros
  • ln left justified with space fillers
# right justified with space fillers
$ nl -n'rn' greeting.txt
     1  Hi there
     2  Have a nice day

# right justified with leading zeros
$ nl -n'rz' greeting.txt
000001  Hi there
000002  Have a nice day

# left justified with space fillers
$ nl -n'ln' greeting.txt
1       Hi there
2       Have a nice day

Customize width

You can use the -w option to specify the width to be used for the numbers (default is 6).

$ nl -w2 greeting.txt
 1      Hi there
 2      Have a nice day

Customize separator

By default, a tab character is used to separate the line number and the line content. You can use the -s option to specify your own custom string separator.

$ nl -w2 -s' ' greeting.txt
 1 Hi there
 2 Have a nice day

$ nl -w1 -s' --> ' greeting.txt
1 --> Hi there
2 --> Have a nice day

Starting number and increment

The -v option allows you to specify a different starting integer. Negative integer is also allowed.

$ nl -v10 greeting.txt
    10  Hi there
    11  Have a nice day

$ nl -v-1 fruits.txt
    -1  banana
     0  papaya
     1  mango

The -i option allows you to specify a positive integer as the step value (default is 1).

$ nl -w2 -s') ' -i2 greeting.txt fruits.txt nums.txt
 1) Hi there
 3) Have a nice day
 5) banana
 7) papaya
 9) mango
11) 3.14
13) 42
15) 1000

Section wise numbering

If you organize your input with lines conforming to specific patterns, you can control their numbering separately. nl recognizes three types of sections with the following default patterns:

  • \:\:\: as header
  • \:\: as body
  • \: as footer

These special lines will be replaced with an empty line after numbering. The numbering will be reset at the start of every section. Here's an example with multiple body sections:

$ cat body.txt
\:\:
Hi there
How are you
\:\:
banana
papaya
mango

$ nl -w1 -s' ' body.txt

1 Hi there
2 How are you

1 banana
2 papaya
3 mango

Here's an example with both header and body sections. By default, header and footer section lines are not numbered (you'll see options to enable them later).

$ cat header_body.txt
\:\:\:
Header
red
\:\:
Hi there
How are you
\:\:
banana
papaya
mango
\:\:\:
Header
green

$ nl -w1 -s' ' header_body.txt

  Header
  red

1 Hi there
2 How are you

1 banana
2 papaya
3 mango

  Header
  green

And here's an example with all the three types of sections:

$ cat all_sections.txt
\:\:\:
Header
red
\:\:
Hi there
How are you
\:\:
banana
papaya
mango
\:
Footer

$ nl -w1 -s' ' all_sections.txt

  Header
  red

1 Hi there
2 How are you

1 banana
2 papaya
3 mango

  Footer

The -b, -h and -f options control which lines should be numbered for the three types of sections. Use a to number all lines of a particular section (other features will discussed later).

$ nl -w1 -s' ' -ha -fa all_sections.txt

1 Header
2 red

1 Hi there
2 How are you

1 banana
2 papaya
3 mango

1 Footer

If you use the -p option, the numbering will not be reset on encountering a new section.

$ nl -p -w1 -s' ' all_sections.txt

  Header
  red

1 Hi there
2 How are you

3 banana
4 papaya
5 mango

  Footer

$ nl -p -w1 -s' ' -ha -fa all_sections.txt

1 Header
2 red

3 Hi there
4 How are you

5 banana
6 papaya
7 mango

8 Footer

The -d option allows you to customize the two character pattern used for sections.

# pattern changed from \: to %=
$ cat body_sep.txt
%=%=
apple
banana
%=%=
red
green

$ nl -w1 -s' ' -d'%=' body_sep.txt

1 apple
2 banana

1 red
2 green

Section numbering criteria

As mentioned earlier, the -b, -h and -f options control which lines should be numbered for the three types of sections. These options accept the following arguments:

  • a number all lines, including empty lines
  • t number lines except empty ones (default for body sections)
  • n do not number lines (default for header and footer sections)
  • pBRE use basic regular expressions (BRE) to filter lines for numbering

If the input doesn't have special patterns to identify the different sections, it will be treated as if it has a single body section. Here's an example to include empty lines for numbering:

$ printf 'apple\n\nbanana\n\ncherry\n' | nl -w1 -s' ' -ba
1 apple
2 
3 banana
4 
5 cherry

The -l option controls how many consecutive empty lines should be considered as a single entry. Only the last empty line of such groupings will be numbered.

# only 2nd consecutive empty line will be considered for numbering
$ printf 'a\n\n\n\n\nb\n\nc' | nl -w1 -s' ' -ba -l2
1 a
  
2 
  
3 
4 b
  
5 c

Here's an example which uses regexp to identify lines to be numbered:

# number lines starting with 'c' or 't'
$ nl -w1 -s' ' -bp'^[ct]' purchases.txt
1 coffee
2 tea
  washing powder
3 coffee
4 toothpaste
5 tea
  soap
6 tea

info See Regular Expressions chapter from my GNU grep ebook if you want to learn about regexp syntax and features.