3

I have a file of 20 lines. I want to search for a string between the lines 10 and 15 and print the string along with the line numbers of the original file.

I have tried sed -n 10,15p file | grep -n "pattern"

The problem with the above command is, the output line number 10 of sed will be line number 1 for grep.

Hence it is not printing the line numbers from the original file.

HalosGhost
  • 4,790
Lokesh
  • 31
  • 1
  • 1
  • 2

3 Answers3

5

When working w/ sed I typically find it easiest to consistently narrow my possible outcome. This is why I sometimes lean on the !negation operator. It is very often more simple to prune uninteresting input away than it is to pointedly select the interesting kind - at least, this is my opinion on the matter.

I find this method more inline with sed's default behavior - which is to auto-print pattern-space at script's end. For simple things such as this it can also more easily result in a robust script - a script that does not depend on certain implementations' syntax extensions in order to operate (as is commonly seen with sed {functions}).

This is why I recommended you do:

sed '10,15!d;/pattern/!d;=' <input

...which first prunes any line not within the range of lines 10 & 15, and from among those that remain prunes any line which does not match pattern. If you find you'd rather have the line number sed prints on the same line as its matched line, I would probably look to paste in that case. Maybe...

sed '10,15!d;/pattern/!d;=' <input |
paste -sd:\\n -

...which will just alternate replacing input \newlines with either a : character or another \newline.

For example:

seq 150 |
sed '10,50!d;/5/!d;=' |
paste -sd:\\n -

...prints...

15:15
25:25
35:35
45:45
50:50
mikeserv
  • 58,310
1

Using nl:

nl file | sed -n '10,15{/pattern/p
}'
muru
  • 72,889
  • 1
    As an alternative to nl you can use cat -n to get line numbering, but that option's not available in all versions of cat; I guess it's a GNU extension. – PM 2Ring Jan 11 '15 at 05:50
  • 1
    @PM2Ring whereas nl is POSIX. – muru Jan 11 '15 at 06:00
  • 1
    @muru - yes, it's POSIX, but your sed isn't. You need a \newline before any }. In most cases ...' -e \} will do instead. The only case I've discovered in which I cannot rely on that to work is for a \newline in the right-hand side of a s///ubstitution. I asked a question about it once, but aside from helpful hints here and there, I have mostly learned how to handle it portably via trial and error. – mikeserv Jan 11 '15 at 06:14
1

Here is an awk solution:

awk '10<=NR && NR<=15 && /pattern/ {print NR,$0}' file

If we must use only sed, then consider:

sed -n '10,15 {/pattern/ {=;p}}' file | sed 'N;s/\n/ /'

sed's = command will only print the line number on a separate line. The second instance of sed above is used to combine every two lines so that the line number appears just before its line.

John1024
  • 74,655