user1496478
user1496478

Reputation: 29

Use sed to replace string - only after pattern match

I have the following XML:

<xml>

    <bean id="bean1"
         class="class1"
         singleton="false">
        <property name="dbPoolName" value="pool"/>
        <property name="dirName" value="myDir"/>
        <!--              <property name="MyProperty" value="5000"/> -->

    </bean>

    <bean id="bean2"
         class="class2"
         singleton="false">
        <property name="dbPoolName" value="pool"/>
        <property name="dirName" value="myDir"/>
        <!--              <property name="MyProperty" value="5000"/> -->

    </bean>

    <bean id="bean3"
         class="class3"
         singleton="false">
        <property name="dbPoolName" value="pool"/>
        <property name="dirName" value="myDir"/>
        <!--              <property name="MyProperty" value="5000"/> -->

    </bean>
</xml>

I need to uncomment the element:

<!--              <property name="MyProperty" value="5000"/> -->

Only inside bean with id "bean3". Then I need to modify its value, so that it is 50 instead of 5000.

I have tried using the following command:

grep -A 4 "bean3" file.xml | sed 's/<!--//' | sed 's/-->//' | sed 's/5000/50/'

But I am not able to replace it in file.

Should I use sed and/or grep?

Upvotes: 1

Views: 2045

Answers (3)

Ed Morton
Ed Morton

Reputation: 203254

$ awk '/<bean id=/{f=(/bean3/?1:0)} f&&gsub(/<!-- *| *-->/,""){sub(/00/,"")} 1' file
<xml>

    <bean id="bean1"
         class="class1"
         singleton="false">
        <property name="dbPoolName" value="pool"/>
        <property name="dirName" value="myDir"/>
        <!--              <property name="MyProperty" value="5000"/> -->

    </bean>

    <bean id="bean2"
         class="class2"
         singleton="false">
        <property name="dbPoolName" value="pool"/>
        <property name="dirName" value="myDir"/>
        <!--              <property name="MyProperty" value="5000"/> -->

    </bean>

    <bean id="bean3"
         class="class3"
         singleton="false">
        <property name="dbPoolName" value="pool"/>
        <property name="dirName" value="myDir"/>
        <property name="MyProperty" value="50"/>

    </bean>
</xml>

Upvotes: 0

e0k
e0k

Reputation: 7161

Here is an AWK script that scans for the bean tag with id="bean3" and uncomments and changes "5000" to "50" until the next bean tag:

#!/usr/bin/awk

BEGIN{ in_bean3 = 0 }
$0~/<bean / {  # match start of bean tag
    if ( $0 ~ "id=\"bean3\"" ) {
        # Set flag for desired context
        in_bean3 = 1
        print
        next
    } else {  # clear flag
        in_bean3 = 0
    }
}
in_bean3 {  # in desired context
    sub(/<!-- */, "")
    sub(/ *-->/, "")
    sub(/"5000"/, "\"50\"")
}
1

Notice the 1 at the end performs the default action of printing the line.

Upvotes: 0

Anthony Geoghegan
Anthony Geoghegan

Reputation: 11983

If you’re using GNU sed, you can do it all with one command:

sed '/bean3/,+5s/<!-- *\|-->//g; /bean3/,+5s/5000/50/' file.xml

You only need to run one instance of the sed command. Individual sed commands are separated with a semicolon, ;. In this case, we only needed two sed commands:

  1. The first substitutes both <!-- (optionally followed by spaces) and --> with an empty string – using the alternation \| operator and the g (global) modifier.
  2. The second simply replaces 5000 with 50.

The /bean3/,+5 range is a GNU extension; this ensures that the above substitutions are only performed on the 5 lines following the first occurrence of bean3. This range is used for both substitution commands.

If you’re confident that the sed commands do what you want, you can use the -i / --in-place option to change file.xml.

Upvotes: 3

Related Questions