Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I would like to number lines according to their content: the first line gets number 1, the second line gets number 2 if it's identical to the first and number 1 if it's different, and so on. For example:


Should result in:

1   asdf
2   asdf
3   asdf
4   asdf
1   dfg
2   dfg
3   dfg
1   qwert
2   qwert
1   er
3   qwert
2   er
5   asdf
share|improve this question
Incremental? You are resetting the counter every time there a new item. Or is it a counter and it should resume if the same token is encountered again? – Matteo Sep 5 '12 at 14:23
The question is underspecified. Please look at the comments on @JohnCC's answer, and update the question to clarify the ambiguity. – jw013 Sep 5 '12 at 16:09

Even simpler with awk:-

awk '{ print ++c[$0],$0 }' < test

Where test is the file that contains the data. I made a couple of assumptions here that are not clear from the question. First, I assume the file is already sorted. If not, then:-

sort < test | awk '{ print ++c[$0],$0 }'

Also, I assume that the whole line is significant, and not just the first word if there should be more than one. If you just want to work on the first word then:-

awk '{ print ++c[$1],$0 }' < test

share|improve this answer
But, if asdf occurs again, it will continue numbering, do I understand that correctly? But this was also not clear from the question. I like your approach. – Bernhard Sep 5 '12 at 15:18
Yes, correct. That was why I asked about sorting, since as you say, the question is not very clear. – JohnCC Sep 5 '12 at 15:20

You could do this with awk:


BEGIN { OFS = "\t" }

last == $1 { cnt += 1}
last != $1 { cnt  = 1 }

{ print cnt, $1; last = $1 }

Run like this:

awk -f number.awk infile
share|improve this answer

You can iterate over the input and use a counter



while IFS= read -r line ; do
    # check if the line is different from the previous one
    if [ "$line" != "$old" ] ; then
    printf '%s\t%s\n' "$counter" "$line"

You can run the script with:

$ sh scriptname.sh < inputfile
share|improve this answer
Thanks, how do I launch this from a tab delimited file? – martijn Sep 5 '12 at 14:57
Edited with tab delimited output – Matteo Sep 5 '12 at 15:21
@Gilles, thanks for the edit. Just a question why printf is better then echo? – Matteo Sep 6 '12 at 5:16
@Matteo With echo -e, if an input line contains a backslash, it would have been interpreted as an escape character. The -r option to read is for the same reason, and IFS= is to retain leading and trailing whitespace, see Why is while IFS= read used so often, instead of IFS=; while read..? – Gilles Sep 6 '12 at 13:28
@Gilles Thanks for the free code review :-) – Matteo Sep 6 '12 at 14:07

If you need something that works independent of whether the input is clustered (i.e. all occurrences of X being after each other) you need to use some counter per each different X. You can e.g. use the following as a filter or with a ommandline parameter, writing to stdout:

#!/usr/bin/env python
import sys, collections
c = collections.Counter()
for line in sys.stdin if len(sys.argv) == 1 else open(sys.argv[1]):
    c[line] += 1
    sys.stdout.write("%s\t%s" % (c[line], line))
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.