【问题标题】:geting string from tags using sed and grep使用 sed 和 grep 从标签中获取字符串
【发布时间】:2019-06-28 08:37:43
【问题描述】:

更新 2 我想我需要这样简单的东西:
Regex with negative lookahead across multiple lines

获取第一个不在父级之前的位置 我试过这个没有成功

((?<![<parent>]))<version>.*

或者这个,但它仍然捕获所有版本的:

(?<!^<parent>)<version>(?!<\/parent>)

如何使用 sed 和 grep 从标签中获取字符串 我尝试捕获标签: <groupId>org.test.proj.assent</groupId> <artifactId>mainapp</artifactId> <version>mainapp.1.4</version> <packaging>pom</packaging> <name>main app 1</name>

然后我想我会从那里提取字符串:

<version>mainapp.1.4</version>

我试过这个:

sed -n '/version/,/version/p' pom.xml | grep -o -e '<version>.*'

但它给了我所有的版本

我也尝试捕捉:

sed -n '/\/artifactId/,/\/version/p' pom.xml | grep -o -e '<version>.*'

但是所有文件都被打印出来了

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" >
    <modelVersion>55.0.0</modelVersion>

    <parent>
        <groupId>org.test.proj</groupId>
        <artifactId>test-invoker</artifactId>
        <version>invoker.0.4</version>
    </parent>

    <groupId>org.test.proj.assent</groupId>
    <artifactId>mainapp</artifactId>
    <version>mainapp.1.4</version>
    <packaging>pom</packaging>
    <name>main app 1</name>

    <properties>
        <app-name>Testing App</app-name>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.prod.db</groupId>
                <artifactId>srver-db</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    </project>

我只能使用没有安装的原生 linux 工具

更新的 xml 和要捕获的字符串

【问题讨论】:

  • 您可以使用专用的XML parsing tool 吗? sedgrep 不支持 XML 语法。
  • 不,我不能纯 linux 工具
  • 是的标准 AWS linux
  • @user63898 您可以添加示例输入并显示输出所需的确切字符串吗?有多个&lt;version&gt; 标签,你需要在什么基础上选择作为输出?是字符串this one i need 还是别的什么?另外,这个标签可以跨多行吗?
  • 不要使用正则表达式解析 XML。或者至少,阅读stackoverflow.com/questions/1732348/…,这样你就知道你在做什么了。

标签: regex xml sed grep


【解决方案1】:

使用 GNU awk:

$ awk '/<project/{next} !s && match($0, /<([a-zA-Z]+)>/, tag){s=1} s && ($0~ "</" tag[1] ">"){s=0} !s && match($0, "<version>([^<]*)</version>", ver) {print ver[1]}' file
mainapp.1.4

$ awk '/<project/{next} !s && match($0, /<([a-zA-Z]+)>/, tag){s=1} s && ($0~ "</" tag[1] ">"){s=0} !s && match($0, "<version>([^<]*)</version>", ver) {print ver[0]}' file
<version>mainapp.1.4</version>

为了便于阅读,多写几行:

awk '/<project/{next} 
    !s && match($0, /<([a-zA-Z]+)>/, tag){s=1} 
    s && ($0~ "</" tag[1] ">"){s=0} 
    !s && match($0, "<version>([^<]*)</version>", ver) {print ver[1]}' file

使用ver[0] 包含标签本身,ver[1] 仅包含innerText。

这是基于所有root标签都会关闭的条件。

【讨论】:

  • 哇这么复杂...我可以用更短更简单的方法来做一些吗?我现在不需要我将使用 grep 管道的内部文本
  • @user63898 考虑到regex的贪婪本性和这个问题的复杂性,我想这并不容易......
  • 非常复杂以至于它是如此复杂,我只是在字符串之间获取文本
  • @user63898 我想这就是他们建议您使用 xml 解析器的原因。而我的awk 解决方案实际上是基于root tags will close 假设而简化的。
【解决方案2】:

如果Perl 可用,如何:

perl -0777 -ne '
    while (m#(<parent>.*</parent>)|(?<=<version>)(.*?)(?=</version>)#sg)
    {print $&, "\n" if $& !~ /(^\$|parent)/}' file.xml

虽然你可能仍然觉得这并不简单:)。

解释:

  • -0777 选项告诉perl slurp 所有行以启用多行上的模式匹配。
  • 正则表达式匹配两种模式:&lt;parent\&gt;..&lt;/parent&gt;&lt;version&gt;..&lt;/version&gt;。前者的目的是在&lt;parent&gt;标签内跳过与&lt;version&gt;标签的匹配。
  • 最后打印匹配的子字符串$&amp;,不包括以'$'开头或包含'parent'的子字符串。
  • 如果我们可以像您提到的那样说(?&lt;!&lt;parent&gt;.*)&lt;version&gt;..,那就简单多了。不幸的是,variable length lookbehind 目前还没有在 Perl(和大多数其他语言)中实现。

【讨论】:

    【解决方案3】:

    问题说明:

    我只能使用没有安装的原生 linux 工具

    并且正在使用的linux版本在评论中描述为:

    是的标准 AWS linux

    我刚刚检查过,Amazon Linux 预装了 xmllint。

    因此,一个解决方案似乎是:

    xmllint --xpath "/*[local-name()='project']/*[local-name()='version']/text()" pom.xml
    

    【讨论】:

      猜你喜欢
      • 2014-01-13
      • 2018-02-24
      • 1970-01-01
      • 1970-01-01
      • 2011-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多