2

How to use the line number with sed?

This question is about understanding, not about completing a specific task.

And, no, Sed to print out the line number has been proposed a second time and does not answer this question better than the first time. I'm specially asking how to access the line number, as printed with = inside a single call of sed. If I really have to use pipes, there are better options then sed '=' , that would include grep -e -n.

Widespread believe is that sed cannot count, but this is wrong.

I have seen https://unix.stackexchange.com/a/707343 and https://linux.die.net/man/1/sed so there is the = command that prints the line number.

What I want to know is, if that line number can be used inside of a single sed call, for example in a replacement string, something like sed 's/^/=&/' which doesn't work as desired but takes the equal sign literally.

I wonder if this is really not possible, or if I just miss the proper syntax.

I'm aware that grep -n -e does the trick, but I would like to know if it is possible with sed alone, in one single call, without pipes, tr, or other helpers.

The main objective is to learn how to handle line numbers with sed,in more complex ways.

Quite obviously, sed can count, otherwise address ranges based on numbers would not be possible. It boils down on how to access the line number.


As for the suggested (false) duplicate Sed to print out the line number my question, as stated above, is about using the line numbers within sed.

11
  • 1
    This question is similar to: Sed to print out the line number. If you believe it’s different, please edit the question, make it clear how it’s different and/or how the answers on that question are not helpful for your problem. Commented Jun 2 at 12:07
  • From the linked answer: sed '=' myfile | sed 'N;s/\n/ /' Commented Jun 2 at 12:09
  • @pLumo sorry, I cannot find anything like that there. Could you give a link t the answer instead of the whole q&a? And my question is how to do it in one sed call, no pipes. If that is possible at all. Commented Jun 2 at 12:21
  • 1
    @pLumo I don't think this is a dupe. The OP isn't asking "how can I use sed specifically to add the line number to the beginning of the line" but is more asking the broader, more general "I know that = can be used in sed to do things with the line number, so what kind of things can it do?". Gyro, it would help if you could tidy up a bit, remove unnecessarily combative words like "superstition" and just ask how = can be used in sed for anything more complex. Commented Jun 2 at 14:07
  • 1
    I completely understand if you're just curious but in case you're unaware - the things you're asking for help to implement with sed became obsolete about half a century ago when awk was invented. For example sed '=' = awk '{print NR ORS $0}', and what I think you're trying to do with sed 's/^/=&/' would be awk '{print NR $0}'). Any time you find yourself attempting to use sed constructs other than s, g, and p (with -n) take a second to think about what you're doing as it'd probably be some combination of clearer, simpler, more robust, more efficient and/or more portable with awk. Commented Jun 2 at 22:53

2 Answers 2

5

sed is a Turing complete language, it can do anything. Someone even implemented dc, the Unix direct calculator in sed.

Compared to that, getting the line number would be trivial, but while sed's language has ready support to match on line number (like with 12,21 { actions; } to run actions on lines 12 to 21) or print the line number (with =), none of those would help if you wanted to insert that line number in the result of a substitution for instance or more generally insert it in the hold or pattern space.

Short of piping the output of = in a separate sed invocation as shown by @pLumo, you're left with incrementing a number by yourself using the kind of technique used by dc.sed like in:

sed 'x;:1 s/$/,,0123456789,0/;s/^,/0,/ s/\(.\),\([^,]*\).*\1\(,*.\).*/\3\2/;/,/b1 x;G;s/\(.*\)\n\(.*\)/line \2 is \1/' 

Remember that sed was a tool written in the 70s on computers with very limited resources. It was mostly made obsolete by awk in the late 70s and of course fully by perl in the late 80s where those things are trivially done:

awk '{print "line "NR" is "$0}' perl -ne 'print "line $. is $_"' 
awk '{$0 = "line "NR" is "$0};1' perl -pe '$_ = "line $. is $_"' 

Or even more sed-like:

awk '{sub(/^/, "line "NR" is ")};1' perl -pe 's/^/line $. is /' 
1
  • "on computers with very limited resources" ... that's one of the reasons I like sed on heavy duty tasks. I guess this is not the site to ask about performance of awk vs. sed on ARM based machines? ("No risc, no fun", eh?) Commented Jun 8 at 11:55
2

With sed only you can do ...

sed '=' myfile | sed 'N;s/\n//' 

For anything more complex, you could use back references, e.g. place the number to the end

sed '=' myfile | sed -E 'N;s/(.*)\n(.*)/\2\1/' 

(I use Extended Regex (-E) for better readability, but you could do the same with Basic Regex).

or behind the x

sed '=' myfile | sed -E 'N;s/(.*)\n(x)(.*)/\2\1\3/' 
4
  • 1
    Are you 100% sure that the only way to use = in sed is to have it print out the number with sed '='? I suspect so since it is a command and not a variable, but I am not sure. Commented Jun 2 at 16:10
  • I suspect so too, but surely not 100% sure. Maybe someone comes up with a better idea. This is the best idea I have though :-) Commented Jun 2 at 19:06
  • Since cat -n adds line numbers another approach would be cat -n myfile |sed -E 's/ +([0-9]+)\t(.*)/\2\1/' Commented Jun 2 at 21:20
  • FWIW the equivalent awk scripts using any awk to the 3 2-seds-plus-a-pipe scripts above would be 1) awk '{print NR $0}' myfile, 2) awk '{print $0 NR}' myfile, and 3) awk '{sub(/x/,"&"NR); print NR ORS $0}' myfile. So, idk when it'd be beneficial to actually use any of the sed+pipe constructs. Commented Jun 2 at 23:06

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.