Sed Find and Replace Between Two Tags with Multi Line

sed find and replace between two tags with multi line

Using sed you can try something like:

sed -e ':a;N;$!ba' -e 's#<file.*</file>#<sometext>\nvalue1\n</sometext>#' file

My sed is a little rusty but what we are doing here is using :a;N;$!ba we effectively create one long line in pattern space so that we can apply the second expression which does your substitution.

This will probably need GNU sed

Test:

$ cat file
hold1
hold2
<file option1='one'>
some text
some text
more data
</file>
this1
that1


$ sed -e ':a;N;$!ba' -e 's#<file.*</file>#<sometext>\nvalue1\n</sometext>#' file
hold1
hold2
<sometext>
value1
</sometext>
this1
that1

Grep/Sed between two tags with multiline

I'd use pcregrep, which can match multiline regexes:

pcregrep -Mo 'test \K((?s).)*?(?=</singleline>)' filename

The tricks are:

  • -M allows pcregrep to match on more than one line,
  • -o makes it print only the match,
  • \K throws away the part of the match that comes before it,
  • (?=</singleline>) is a lookahead term that matches an empty string if (and only if) it is followed by </singleline>, and
  • ((?s).)*? to match any characters non-greedily, which is to say that if you have several occurrences of </singleline> in the file, it will match until the closest rather than the furthest. If this is not desired, remove the ?. (?s) enables the s option locally for the term to make . match newlines in it; it wouldn't do that by default.

Thanks to @CasimiretHippolyte for pointing out the ((?s).) alternative to (.|\n).

sed to match multiline range and replace

If we can assume you have the URL on the second line below second: you may use

sed -i '/second:/{N;N;s#"http://.*"#"next.com"#}' file

See this online sed demo.

N appends the newline and then subsequent line to the pattern space. So, the substitute command is run on the following text:

second:
{
host = "http://nxt-secondepisode.xcfm.crata.dive.com/err1.2.2/table/kenny.xml.gz"

If it is not known which line it is exactly, you may loop before you find the lione that starts with 0+ spaces, then host =, and only then run substitution:

sed -i '/second:/{:a;n;/^ *host *=/!ba;s#"http://.*"#"next.com"#}' file

See this online sed demo.

Here,

  • /second:/ - once a line contains second:
  • :a - set a label named a
  • n - discard the current pattern space and read the next line into it
  • /^ *host *=/!ba - if the line does not (!) start with 0+ spaces, host, 0+ spaces, =, then go back (b) to label a position
  • s#"http://.*"#"next.com"# - run the substitution.

Literal spaces can be replaced with [[:space:]]*, [[:blank:]]* or \s* to match any whitespace depending on what works in your sed.

Sed regexp multiline - replace HTML

While @nhahtdh's answer is the correct one for your original question, this solution is the answer to your comments:

sed '
/<!-- PAGE TAG -->/,/<!-- PAGE TAG -->/ {
1 {
s/^.*$/Replace Data/
b
}
d
}
'

You can read it like so:

/<!-- PAGE TAG -->/,/<!-- PAGE TAG -->/ -> for the lines between these regexes

1 { -> for the first matching line

s/^.*$/Replace Data/ -> search for anything and replace with Replace Data

b -> branch to end (behaves like break in this instance)

d -> otherwise, delete the line

You can make any series of sed commands into one-liners with gnu sed by adding semicolons after each command (but it's not recommended if you want to be able to read it later on):

sed '/<!-- PAGE TAG -->/,/<!-- PAGE TAG -->/ { 1 { s/^.*$/Replace Data/; b; }; d; };'

Just as a side note, you should really try to be as specific as possible in your posting. "replaced/removed" means "replaced OR removed". If you want it replaced, just say replaced. That helps both those of us trying to answer your question and future users who might be experiencing the same issue.

Use sed to Replace Multiple Lines

This might work for you (GNU sed):

sed '/second/,/fourth/cfound' file

or for those line numbers:

sed '2,4cfound' file

Replace a word with multiple lines using sed?

If you build your multiple line text with "\n"s, this will work with a simple sed command as:

DATA=`echo ${DATA} | tr '\n' "\\n"`
#now, DATA="line1\nline2\nline3"
sed "s/_data_/${DATA}/" mail.tpl


Related Topics



Leave a reply



Submit