简体   繁体   中英

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?

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 .

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.

$ 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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM