0

I'm trying to edit my pom.xml file with a script. It involves inserting a plugin module after one that I expect to exist.

My reduced pom looks something like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>very</groupId>
    <artifactId>secret</artifactId>
    <version>2.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Something</name>

    <properties>
    ...
    </properties>

    <modules>
        <module>...</module>
    </modules>

    <prerequisites>
        ...
    </prerequisites>

    <profiles>
        <profile>
        ...
        </profile>
    </profiles>

    <dependencyManagement>
        <dependencies>
            <dependency>
                ...
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                ... 
                </plugin>
            </plugins>
        </pluginManagement>

        <plugins>
            <plugin>
            ...
            </plugin>
            <plugin>
                <groupId>org.zeroturnaround</groupId>
                <artifactId>jrebel-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>Generate JRebel configuration</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <relativePath>${relativeRoot}</relativePath>
                    <rootPath>$${webapp.jrebel.root}</rootPath>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <reporting>
        <plugins>
            <plugin>
            ...
            </plugin>
        </plugins>
    </reporting>

</project>

I want to use a script to add another plugin after the zeroturnaround one. So basically I am looking for this pattern:

                <rootPath>$${webapp.jrebel.root}</rootPath>
            </configuration>
        </plugin>

And would like to insert something after this pattern. So the output should be

                <rootPath>$${webapp.jrebel.root}</rootPath>
            </configuration>
        </plugin>
        Something new here

sed doesn't work because the inputs come in line by line. So this

sed '/<rootPath>\$\${webapp.jrebel.root}<\/rootPath>/a Something new here' pom.xml

prints out

               <rootPath>$${webapp.jrebel.root}</rootPath>
      Something new here
            </configuration>
        </plugin>

I have tried

sed -i -e '/<rootPath>\$\${webapp.jrebel.root}<\/rootPath>/ {
N; /\n<\/configuration>/ {
N; /\n<\/plugin>/ {
s/<\/plugin>/<\/plugin>hello/
}
}
}' pom.xml

But that does nothing.

How can I pattern match this? I am open to using either sed or awk.

Somaiah Kumbera
  • 7,063
  • 4
  • 43
  • 44

3 Answers3

2

With xmlstarlet, you would say something like:

 xmlstarlet ed -a //plugin -t elem -n whatever -s //whatever -t elem -n stuff pom.xml
Michael Vehrs
  • 3,293
  • 11
  • 10
  • 1
    I ended up using this command: xmlstarlet ed -N p=http://maven.apache.org/POM/4.0.0 -a "/p:project/p:build/p:plugins/p:plugin" -t elem -n my-new-element -v "" pom.xml – Somaiah Kumbera Jun 09 '16 at 09:12
  • 1
    These two questions also helped me: http://stackoverflow.com/questions/29347088/edit-xml-element-with-xmlstarlet-shows-no-effect http://stackoverflow.com/questions/7473720/how-do-i-insert-an-element-directly-after-another-element-with-xmlstarlet – Somaiah Kumbera Jun 09 '16 at 09:13
1

Using XML tools to manipulate XML is good advice. Havign said that, using GNU awk for multi-char RS, this may be adequate for your needs:

$ cat file1
                <rootPath>$${webapp.jrebel.root}</rootPath>
            </configuration>
        </plugin>

$ cat file2
foo
                <rootPath>$${webapp.jrebel.root}</rootPath>
            </configuration>
        </plugin>
bar

$ awk -v RS='^$' -v ORS= -v new='Something new here' '
NR==FNR { old=$0; lgth=length(old); next }
start=index($0,old) {
    $0=substr($0,1,start+lgth-1) "\t" new "\n" substr($0,start+lgth)
}
1' file1 file2
foo
                <rootPath>$${webapp.jrebel.root}</rootPath>
            </configuration>
        </plugin>
        Something new here
bar

Here's the syntax if you don't have the "old" string in a file but just want to hard-code it in an awk variable instead:

$ awk -v RS='^$' -v ORS=  \
-v old='
                <rootPath>$${webapp.jrebel.root}</rootPath>
            </configuration>
        </plugin>
' \
-v new='Something new here' '
start=index($0,old) {
    lgth=length(old)
    $0=substr($0,1,start+lgth-1) "\t" new "\n" substr($0,start+lgth)
}
1' file2
foo
                <rootPath>$${webapp.jrebel.root}</rootPath>
            </configuration>
        </plugin>
        Something new here
bar

With other awks you'd build up the strings line by line then make the change in the END section:

awk -v ORS= -v new='Something new here' '
NR==FNR { old = old $0 RS; next }
{ xml = xml $0 RS }
END {
    if ( start=index(xml,old) ) {
        lgth=length(old) 
        xml=substr(xml,1,start+lgth-1) "\t" new "\n" substr(xml,start+lgth)
    }
    print xml
}
' file1 file2
foo
                <rootPath>$${webapp.jrebel.root}</rootPath>
            </configuration>
        </plugin>
        Something new here
bar
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • Hi Ed thanks for quick response. But do I really need file2? – Somaiah Kumbera Jun 08 '16 at 13:45
  • Yes. file1 contains the multi-line string you want to search for in file2. file2 is your XML document that contains that string in the middle of a bunch of other text (foo and bar in my example). The thing you don't NEED is file1 as you could set that as a variable on the command line but I just find it convenient to store the multi-line string in a file instead. – Ed Morton Jun 08 '16 at 13:47
  • Ok that answers my question. Thanks! Will try this out tomorrow and accept if all is well. – Somaiah Kumbera Jun 08 '16 at 13:48
  • OK, just FYI I added an example showing how you'd do it without file1. – Ed Morton Jun 08 '16 at 13:51
  • Upvoted, but didn't accept this as the answer, because I went with the cleaner option of using xmlstarlet, as suggested by @Michael Vehrs. Thanks for a detailed solution. – Somaiah Kumbera Jun 09 '16 at 09:11
-1

Not ideal, but, if you insist in using sed, you can try something like this :

#!/bin/bash
for linenumber in `sed -n '/webapp.jrebel.root/=' pom.xml`
do
    sed -n $linenumber','$(($linenumber + 3))'p' pom.xml > tmpfile
    if [[ `sed -n  '/<\/configuration>/=' tmpfile` == 2 && `sed -n  '/<\/plugin>/=' tmpfile` == 3 ]]
    then
        sed -i $(($linenumber + 3))'i\Something new here\n' pom.xml
    fi
done
slashcool
  • 168
  • 7