nl

If the numbering options provided by cat isn't enough, nl might suit you better. 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 numbers 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 greeting.txt
     1  Hi there
     2  Have a nice day

$ 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 step value

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 an 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

$ nl -w1 -s'. ' -v8 -i-1 greeting.txt fruits.txt
8. Hi there
7. Have a nice day
6. banana
5. papaya
4. mango

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
teal
\:\:
Hi there
How are you
\:\:
banana
papaya
mango
\:\:\:
Header
green

$ nl -w1 -s' ' header_body.txt

  Header
  teal

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
teal
\:\:
Hi there
How are you
\:\:
banana
papaya
mango
\:
Footer

$ nl -w1 -s' ' all_sections.txt

  Header
  teal

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 teal

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
  teal

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 teal

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
%=%=
teal
green

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

1 apple
2 banana

1 teal
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 the 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 regular expressions to identify the 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 the Regular Expressions chapter from my GNU grep ebook if you want to learn more about regexp syntax and features.

Exercises

info The exercises directory has all the files used in this section.

1) nl and cat -n are always equivalent for numbering lines. True or False?

2) What does the -n option do?

3) Use nl to produce the two expected outputs shown below.

$ cat greeting.txt
Hi there
Have a nice day

# expected output 1
##### add your solution here
001     Hi there
002     Have a nice day

# expected output 2
##### add your solution here
001) Hi there
002) Have a nice day

4) Figure out the logic based on the given input and output data.

$ cat s1.txt
apple
coffee
fig
honey
mango
pasta
sugar
tea

##### add your solution here
15. apple
13. coffee
11. fig
 9. honey
 7. mango
 5. pasta
 3. sugar
 1. tea

5) What are the three types of sections supported by nl?

6) Only number the lines that start with ---- in the format shown below.

$ cat blocks.txt
----
apple--banana
mango---fig
----
3.14
-42
1000
----
sky blue
dark green
----
hi hello

##### add your solution here
 1) ----
    apple--banana
    mango---fig
 2) ----
    3.14
    -42
    1000
 3) ----
    sky blue
    dark green
 4) ----
    hi hello

7) For the blocks.txt file, determine the logic to produce the expected output shown below.

##### add your solution here

1. apple--banana
2. mango---fig

1. 3.14
2. -42
3. 1000

1. sky blue
2. dark green

1. hi hello

8) What does the -l option do?

9) Figure out the logic based on the given input and output data.

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

##### add your solution here

 1) Header
 2) teal

 3) Hi there
 4) How are you

 5) banana
 6) papaya
 7) mango

    Footer