4

I'm trying to substitute (with sed) an entire line containing a specific word and the newline at the end. Here the testfile:

this # target for substitution
this is a test
another test?

Now, I already posted here, and from the linked post, I understand how to do this in some way:

sed 's/^this$/test/g' testfile

That works, or at least it seems so, because the newline at the end of the word this is still there:

test # target for substitution but newline is still there
this is a test
another test?

Given the above, I'm also fully aware sed can't match the newline directly (although I do recall that I could use '\n' in certain version of sed, but that's beside the point).

I do know how to at least delete the entire word/line and the newline:

sed '/^this$/d' testfile

Except I need to substitute it instead.

How can I do this? (with sed preferably)

14
  • 1
    When you also remove the newline, you effectively substitute the lines this and this is a test by a single line testthis is a test. Is that correct? It's not easy to join two lines together in sed; see examples in the manual. You could use awk, which can read the next line: awk -v replacement=test '/^this$/ { getline; print replacement $0 }' testfile – berndbausch May 10 at 5:30
  • Yes, that is absolutely correct (and coincidentally exactly what i want here) @berndbausch And I always thought it feasible to join two lines together in sed, especially since i vaguely recall doing it once, but don't quote me on that as I'm unsure and don't remember what i did in sed for this...Lastly I really prefer doing this in sed if possible, otherwise awk might be fine if that's really the only way – Nordine Lotfi May 10 at 5:34
  • 1
    Does this work? awk '{if (/^this$/) {sub(/^this$/, "test"); printf "%s", $0;} else print }' file – Prabhjot Singh May 10 at 5:56
  • 1
    @berndbausch Why shouldn't it be easy to joing two lines in sed? There is the N command for this. Nothing more simple. – Philippos May 10 at 6:35
  • 1
    @NordineLotfi In all sed versions, you can match a newline in the search pattern with \n. What you recall applies to the replacement pattern. – Philippos May 10 at 6:38
7

As I understand you, you want to replace a line consisting only of the word this and the following newline by test, so

foo
this
this is a test

should become

foo
testthis is a test

In sed you can do simply join the next line with N and replace everything up to the newline:

sed '/^this$/{N;s/.*\n/test/;}'
1
  • Better than mine, Nice :) (and learned a new sed trick too) – Nordine Lotfi May 10 at 7:44
5

I'd suggest to use perl here, syntax isn't that different from sed for this case:

$ cat ip.txt
this
this is a test
another test?

$ perl -pe 's/^this\n/XYZ/' ip.txt
XYZthis is a test
another test?
1
  • 1
    yeah, too bad you can't directly use newline like this, otherwise would make things easier when using sed...Thanks for this alternative – Nordine Lotfi May 10 at 5:43
5

With GNU sed, you can read all lines into memory with -z and do the matching from there, e.g.:

sed -z 's/this\n/test/'
2
  • Interesting. Seems like using the -z flag make the use of \n work as expected... – Nordine Lotfi May 10 at 22:16
  • 1
    @NordineLotfi: with -z sed assumes the data is delimted by NUL chars (\0). For normal files this results in the whole file being read into memory before the sed-script is run. – Thor May 11 at 15:56
3

Turn out doing this, or as other have pointed out "joining" lines in sed is possible:

sed ':a;/^this$/{N;s/\n//;ba}' testfile

result:

thisthis is a test
another test?

To also do substitution:

sed 's/^this$/test/g;:a;/^test$/{N;s/\n//;ba}' testfile
testthis is a test
another test?

Taken from this answer.

2

One way using awk by manipulating the output record separator:

$ awk '{ ORS = sub(/^this$/,"FOO") ? "" : RS }1' file

$ sed -e '
    $!N
    s/^this\n/FOO/;t
    P;D
' file
1

Using awk:

awk '/^this$/{$0="test"}1'  file

In this command, if pattern is found then this is replaced by replacement.

The remaining work is to remove newline after replacement because newline is still there. printf would do that work because unlike print this doesn’t add newline at the end by default.

This is:

awk '/^this$/{printf "%s", "test"; next} 1'   file

And this works.

2
  • 2
    Nice idea, you can simplify it to awk '/^this$/{printf "%s", "test"; next} 1' – Sundeep May 10 at 7:16
  • @Sundeep Thanks. Answer edited. – Prabhjot Singh Jun 8 at 16:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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