【问题标题】:Bash pattern match over multiple lines in pom.xml在 pom.xml 中多行的 Bash 模式匹配
【发布时间】:2016-06-08 12:40:57
【问题描述】:

我正在尝试使用脚本编辑我的 pom.xml 文件。它涉及在我期望存在的插件模块之后插入一个插件模块。

我的简化 pom 看起来像这样:

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

我想使用脚本在 zeroturnaround 之后添加另一个插件。所以基本上我正在寻找这种模式:

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

并且想在这个模式之后插入一些东西。所以输出应该是

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

sed 不起作用,因为输入是一行一行的。所以这个

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

打印出来

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

我试过了

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

但这无济于事。

如何进行模式匹配?我愿意使用 sed 或 awk。

【问题讨论】:

  • 股票建议:不要使用sed 等面向行的工具操作 XML 数据。请改用xmlstarletxsltproc 之类的东西。
  • 好点 - 我现在正在研究 xmllint
  • xmllint 不用于编辑。看起来我需要按照您的建议使用 xmlstarlet @MichaelVehrs

标签: bash awk sed


【解决方案1】:

使用xmlstarlet,您可以这样说:

 xmlstarlet ed -a //plugin -t elem -n whatever -s //whatever -t elem -n stuff pom.xml

【讨论】:

【解决方案2】:

使用 XML 工具来操作 XML 是一个不错的建议。 Havign 说,将 GNU awk 用于多字符 RS,这可能足以满足您的需求:

$ 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

如果您在文件中没有“旧”字符串但只想将其硬编码到 awk 变量中,请使用以下语法:

$ 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

使用其他 awk,您可以逐行构建字符串,然后在 END 部分进行更改:

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 感谢您的快速回复。但我真的需要 file2 吗?
  • 是的。 file1 包含您要在 file2 中搜索的多行字符串。 file2 是您的 XML 文档,它在一堆其他文本(在我的示例中为 foo 和 bar)中间包含该字符串。您不需要的是 file1,因为您可以在命令行上将其设置为变量,但我发现将多行字符串存储在文件中很方便。
  • 好的,这回答了我的问题。谢谢!明天试试这个,如果一切顺利的话就接受。
  • 好的,仅供参考,我添加了一个示例,展示了没有 file1 的情况。
  • 赞成,但不接受这个作为答案,因为我选择了使用 xmlstarlet 的更简洁的选项,正如@Michael Vehrs 所建议的那样。感谢您提供详细的解决方案。
【解决方案3】:

不理想,但是,如果你坚持使用 sed,你可以试试这样:

#!/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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-09
    • 2020-04-02
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    • 2018-01-28
    • 2023-03-28
    相关资源
    最近更新 更多