I usually do this

$ wc questions
  33   36 3105 questions
$ seq 1 33 > nums
$ paste nums questions
1       Content
2       ...
33      End Content

but I feel there could be faster way to do this, without the bad-looking dummy file. How with some basic *ix -tool? Any simpler way to do it? I use Vim so I am happy also with Vim-based solution but simple unix-based solution also works (actually probably better in some cases, I can always spawn inside the editor).

Below a general case.




1. A
2. B
3. C
N. X

Just for the completeness of this list, sed can also do it:

sed '=' questions | sed 'N;s/\n/. /'

Sadly the = command prints the line numbers on separate line, so only a separated sed call can beautify the formatting.


This is exactly what nl is for. For example, assuming file.txt contains your sample input, and you want it to look like your sample output, you could do:

nl -nln '-s. ' file.txt

The manpage for nl goes into greater detail on its use. It gives you a lot of control over the output format.

  • Wow. I've been using *IX since the mid 1980's and I'd never used or heard of nl. – Kyle Jones Mar 8 '12 at 4:37
  • I had to look it up, but according to FreeBSD, it dates to SVR2. – James Sneeringer Mar 8 '12 at 4:46
  • surely not POSIX. It's not on OpenBSD. Though I knew it existed before but I will strongly advise not to use it in scripts. A little "idx=0;for i in cat file; do echo $idx $i; idx=eval $idx + 1 ; done" should do the trick (didn't test, but surely you see the point). You could use an editor like vim/view to look at the file and configure it to print line numbers too, you'll have syntax colors as well hey. – Aki Mar 8 '12 at 5:10
  • 2
    @Aki: The FreeBSD manpage from 4.7-RELEASE onward claims it conforms to POSIX.1, and it's listed in the Single Unix Specification version 2. – James Sneeringer Mar 8 '12 at 14:21
  • 5
    To number all line, it also needs -ba. otherwise it numbers only non-blank lines and yet still prints the un-numbered blank lines, meaning that the line numbers don't increment to reflect the actual number of newlines... This fixes it: nl -nln -ba -s'. ' – Peter.O Mar 8 '12 at 23:11

I'm surprised cat -n hasn't been mentioned by now.

  • 3
    Too standard. It can make things portable... – Aki Mar 8 '12 at 5:13
  • I just mentioned that cat -n in another comment. I was surprised that the -n option isn't part of the Single Unix Specification. – D.Shawley Mar 8 '12 at 22:36

In Vim you could add line numbers to the actual text of a buffer like this:

:%s/^/\=printf('%5d. ',line('.'))

The \= (see :help sub-replace-expression) lets the replacement string be treated as a VimL expression. The expression used here is a simple formatting of the current line number.

You could make it a bit fancier by automatically calculating and using a minimal width (instead of the “hard coded” 5, as above) for the current number of lines in the file:

:%s/^/\=printf('%*d. ',len(line('$')),line('.'))

Or, left-justified:

:%s/^/\=printf('%d.%*s ',line('.'),len(line('$'))-len(line('.')),'')

Of course, if you just want to see the line numbers and do not care to have them actually in the buffer’s data, then you should just use

:set number

From the shell, you might find cat -n or pr -tn useful.

  • Sweet. He could even map the commands to a key. But for the first example I'd rather write a shell script and execute it than open the file on vim and enter this command each time (or press a key) and quit vim then print my file. – Aki Mar 8 '12 at 5:12

Not sure what your constraints are regarding the separation between the number and the data, but i'd do: grep -n '^' questions. That would output:


33:End Content
  • 1
    Using just . as the regex, it will not output blank lines... Using '.*' will . – Peter.O Mar 8 '12 at 8:10
  • 2
    So will ^ as the regex. – Ladadadada Mar 8 '12 at 17:13

Some other solutions:

Exactly what you were doing, without the temporary file:

seq 1 $(wc -l questions | cut -f 1 -d " ") | paste - questions

But cat -n is much better as above fails if the questions file change between the call to wc and paste.

If you want to avoid creating a process you could:

{ N=1; while read line; do printf "%d %s\n" $N "$line"; N=$(($N + 1)); done; } < questions

But do not try the above if you have a large file, especially because the following bash bug.

  • You can spare the cut. When wc processes STDIN outputs no file name: seq 1 $(wc -l < questions) | paste - questions – manatwork Mar 16 '12 at 15:59
  • In this case, cut does not process STDIN output, it process the questions file. – jfg956 Mar 16 '12 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy