4

Given is input_file:

1
2
START
foo
END
3

Goal is to replace content inside including START ... END block with multi-line content from stdin:

1
2
hello 
world
3

What I tried:

sed '/^START$/,/^END$/d;r /dev/stdin' input_file <<EOF 
hello
world
EOF

unfortunately results in

1
hello
world
2
3

I guess r /dev/stdin is invoked sequentially after /^START$/,/^END$/d; and just appends after first line.

Second try:

sed '/^START$/,/^END$/{d;r /dev/stdin
}' input_file <<EOF     
hello
world
EOF

prints

1
2
3

Why do above commands - especially last one - do print the wrong result? And how might I adjust these?

1 Answer 1

6

In your first try, the address range is valid for the d only. The r /dev/stdin (append...) is done for the first line; thereafter, it runs into end-of-file. In your second try, the script doesn't encounter the r command. man sed:

  d      Delete pattern space.  Start next cycle.

So everything after the d command is lost (in the relevant address range); it just doesn't r /dev/stdin.

Try this to achieve yout target:

sed -e '/^START$/,/^END$/ { r /dev/stdin' -e';d};' file3 <<EOF 
hello
world
EOF

1
2
hello
world
3

read is the first thing when address range is met, then delete the address range.

3
  • Both your explanation and solution were extremely helpful. Thanks! Commented Jan 22, 2022 at 16:52
  • Just out of curiousity, is there any value in splitting the sed script to two -e expressions (except maybe for clarity and readability)? Commented Jan 23, 2022 at 8:07
  • the file name that is bein read has to be terminated, either by a <NL> char, or by a '; that's where the -e comes from. Try without! Commented Jan 23, 2022 at 19:53

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.