3

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.

Input

A
B
C
.
.
X

Output

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

6 Answers6

17

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.

James Sneeringer
  • 2,512
  • 13
  • 14
  • Wow. I've been using *IX since the mid 1980's and I'd never used or heard of `nl`. – Kyle Jones Mar 08 '12 at 04:37
  • I had to look it up, but according to FreeBSD, it dates to SVR2. – James Sneeringer Mar 08 '12 at 04: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 08 '12 at 05:10
  • I remember `nl` from late-80s Unix tutorials, listed along with command such as `cat` and `ls`. It made a lot of sense in the days of dot matrix printouts and sprocket paper, but it has its place and I still find call for it. – Alexios Mar 08 '12 at 09:32
  • 2
    @Aki: The [FreeBSD manpage](http://www.freebsd.org/cgi/man.cgi?query=nl&apropos=0&sektion=1&manpath=FreeBSD+4.7-RELEASE&arch=default&format=html) from 4.7-RELEASE onward claims it conforms to POSIX.1, and it's listed in the [Single Unix Specification](http://pubs.opengroup.org/onlinepubs/007908799/xcu/nl.html) version 2. – James Sneeringer Mar 08 '12 at 14:21
  • @Aki you can use `cat -n` in many cases. I'm not sure if the `-n` option is an extension or POSIX. I know that it is not listed in SUS but [Rob Pike was complaining about it in 1983](http://harmful.cat-v.org/cat-v/). – D.Shawley Mar 08 '12 at 22:34
  • 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 08 '12 at 23:11
  • Nice catch, Peter! – James Sneeringer Mar 09 '12 at 02:51
13

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

Kyle Jones
  • 14,845
  • 3
  • 40
  • 51
5

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.

manatwork
  • 30,549
  • 7
  • 101
  • 91
4

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.

Chris Johnsen
  • 19,790
  • 8
  • 63
  • 52
  • 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 08 '12 at 05:12
1

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:

1:Content
2:...


33:End Content
Frederik Deweerdt
  • 3,722
  • 17
  • 18
0

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.

jfg956
  • 5,988
  • 3
  • 22
  • 24
  • 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