Search code examples
shellawksed

Replace content of one line by checking previous and next line


I am trying to replace content by checking previous lines as well as the next line. As shown below.

<Info>
<pInfo>"eth0"</pInfo>
<IpAdd>192.168.1.2</IpAdd>
<port>1123</port>
</Info>
<Info>
<pInfo>"eth1"</pInfo>
<IpAdd>192.168.1.22</IpAdd>
<port>6789</port>
</Info>
<User>
<avl>"Name"</avl>
<IpAdd>192.168.1.2</IpAdd>
<port>1123</port>
</User>

Replace <IpAdd>any IP address</IpAdd> with <IpAdd>111.111.111.111</IpAdd> for which the next line is <port>1123</port> and it should be under <Info><pInfo>"eth0"</pInfo> section.

What I tried:

sed -E "/<Info>/{n;/<pInfo>/{n;s@<IpAdd>.*<([^\n]*\n[^\n]*<port>1123</port>)@<IpAdd>111.111.111.111<@}}" test.txt

Want to replace in the line above port 1123. If I remove ([^\n]*\n[^\n]*<port>1123</port>), then it replaces both ips under Info.

<Info>
<pInfo>"eth0"</pInfo>
<IpAdd>111.111.111.111</IpAdd>
<port>1123</port>
</Info>
<Info>
<pInfo>"eth1"</pInfo>
<IpAdd>111.111.111.111</IpAdd>
<port>6789</port>
</Info>
<User>
<avl>"Name"</avl>
<IpAdd>192.168.1.2</IpAdd>
<port>1123</port>
</User>

Expect:

<Info>
<pInfo>"eth0"</pInfo>
<IpAdd>111.111.111.111</IpAdd>
<port>1123</port>
</Info>
<Info>
<pInfo>"eth1"</pInfo>
<IpAdd>192.168.1.22</IpAdd>
<port>6789</port>
</Info>
<User>
<avl>"Name"</avl>
<IpAdd>192.168.1.2</IpAdd>
<port>1123</port>
</User>

Solution

  • This might work for you (GNU sed):

    sed -E '/<Info>/{:a;N;/<\/Info>$/!ba
            s/(<IpAdd>).*(<\/IpAdd>\n<port>1123<\/port>)/\1111.111.111.111\2/}' file
    

    Gather up the lines between <Info> and </Info> and then match the two lines within the collection that start with <IpAddr> and end with 1123</port> and replace the old address with the new address.