4

I need to add a line with bar before each line with foo with sed.

I need to do this in a Makefile and so I cannot use i\ because it needs a newline in standard sed (not GNU sed, e.g., the one in Mac OS X) and this cannot be done in a Makefile (at least, not nicely).

The solution I found is:

sed '/foo/{h;s/.*/bar/;p;g;}' < in > out

This saves the line, replaces its contents with bar, prints the new line, restores the old line (and prints it by default).

Is there a simpler solution?

lhf
  • 70,581
  • 9
  • 108
  • 149
  • Motivated by http://stackoverflow.com/questions/31148767/error-in-makefile-calling-sed-with-comment-character. – lhf Jul 01 '15 at 01:27

2 Answers2

3

BSD sed

This will put bar before every line with foo:

sed $'/foo/{s/^/bar\\\n/;}' in >out

GNU sed

This will put bar before every line with foo:

sed '/foo/{s/^/bar\n/;}' in >out

How it works

  • /foo/

    This selects lines that contain foo.

  • s/^/bar\n/

    ^ matches the beginning of the line. Thus, for the selected lines, this substitutes in bar\n at the beginning of the line. This effectively adds a new line to precede the one containing foo.

    Under GNU, one can write \n and sed interprets it as a newline. This doesn't work under BSD sed. Hence the different version.

Kevin
  • 53,822
  • 15
  • 101
  • 132
John1024
  • 109,961
  • 14
  • 137
  • 171
  • @lhf Wow, that is limiting. I did [some reading](http://stackoverflow.com/questions/1421478/how-do-i-use-a-new-line-replacement-in-a-bsd-sed) and updated the answer with something that reportedly should work. – John1024 Jul 01 '15 at 02:11
  • You don't actually need the braces, `$'/foo/s/^/bar\\\n/'` works. Though it can be easier to lose track of which part you're looking at. – Kevin Jul 01 '15 at 02:37
  • the gnu one can be trimmed a little bit: `s/^.*foo/bar\n&/`. – Jason Hu Jul 01 '15 at 02:59
  • @HuStmpHrrr I presume that, for BSD, your version would become `$'s/^.*foo/bar\\\n&/'`. I would add it to the answer if I could test it on OSX to be sure. – John1024 Jul 01 '15 at 03:05
  • @John1024 sorry, i have no idea about BSD. – Jason Hu Jul 01 '15 at 03:07
1

This might work for you (GNU sed):

sed '/foo/ibar' file

I'm not sure why you say you need a newline but just incase the inserted line needs to longer than one line you can employ bash so:

sed $'/foo/ibar\\\nbaz' file
potong
  • 55,640
  • 6
  • 51
  • 83