Reputation: 1051
I thought I understood sed but I guess not. I have the following two files, in which I want to replace the "why" and "huh" lines with one different line. No whitespace at all.
test.txt:
hi
why
huh
hi
why
huh
test2.txt:
1
hi
why
huh
hi
why
huh
The following two commands give the following results:
sed "N; s/<why\/>\n<huh\/>/yo/g" test.txt > out.txt
out.txt:
hi
why
huh
hi
yo
sed "N; s/<why\/>\n<huh\/>/yo/g" test2.txt > out2.txt
out2.txt:
1
hi
yo
hi
why
huh
What am I not understanding about sed? Why don't both output files contain the following:
hi
yo
hi
yo
Upvotes: 12
Views: 40391
Reputation: 41
The reason why it didn't replace both pairs of lines is explained beautifully in brandizzi's answer.
However, if we take one step further. Say we have the following file and we want to replace "apple\njuice" with "pure\nmilk".
test.txt
water water water water
water water water apple
juice water water apple
juice water water water
The pattern filter way would not work.
sed '/apple/ {N; s/apple\njuice/pure\nmilk/g}' test.txt
water water water water
water water water pure
milk water water apple
juice water water water
Because the 2nd apple from test.txt, which has been concatenated to the previous line by N, didn't get caught by pattern filter.
One solution I can think of is to use branch to concatenate all lines and then do the replacement.
sed ':a;N;$!ba;s/apple\njuice/pure\nmilk/g' test.txt
water water water water
water water water pure
milk water water pure
milk water water water
It looks dumb, but I haven't think of a better way yet.
Upvotes: 4
Reputation: 27050
Your expression is almost correct, but it has two problems:
If you want to match why
as a word, you should put \<
and \>
around it. You did put just <
and \/>
around it. So, the first correction is:
$ sed 'N; s/\<why\>\n\<huh\>/yo/g' test.txt
But it will not work, either:
$ sed 'N; s/\<why\>\n\<huh\>/yo/g' test.txt
hi
why
huh
hi
yo
Why does it replace only the second pair of lines? Well, in the first line, the N
command will concatenate why
to hi
, leaving in the pattern space the string hi\nwhy
. This string is not matched by the s///
command, so the line is just printed. Next time, you have the string huh
in the pattern space and concatenate hi
to it. Just in the next line you will have why\nhuh
in the pattern space to be replaced.
The solution is to concatenate the next line only when your current line is why
, using the address /^why$/
:
$ sed '/^why$/ {N; s/\<why\>\n\<huh\>/yo/g}' test.txt
hi
yo
hi
yo
Upvotes: 13
Reputation: 36262
This should work for test.txt
file:
sed '/hi/! { N ; s/why\nhuh/yo/ }' test.txt
It means:
When not found hi
in a line (it will be why
), read next one and substitute all it with yo
. Otherwise print directly (when hi
).
Output:
hi
yo
hi
yo
Upvotes: 1