【问题标题】:grep or sed — need to extract a particular textgrep 或 sed — 需要提取特定文本
【发布时间】:2013-05-24 23:33:39
【问题描述】:

如何仅提取匹配文本的子字符串。

我有一个包含多行的 XML 文件。然而,这是我所关心的。

<url>/localhost/index.html</url>

我试过了

cat file.txt | grep -o '<url>.*</url>' 

它给了我整条线。我只想打印/localhost/index.html。有没有其他我可以使用的选项,就像我在 Python 中知道的那样,您可以将正则表达式分组到子组中,然后选择您要打印的那个。

【问题讨论】:

  • XML 文件 = XML 解析器
  • 我不想使用解析器,我想要一个简单的命令行用法。当我想在命令行上执行此操作时,XML 解析器没有意义。 @ruakh
  • @squiguy 所说的话有很大的真实性。只要您的 XML 已格式化以便它们工作,您就可以摆脱正则表达式,但是如果您在一行上有多个 &lt;url&gt;...&lt;/url&gt; 条目,例如,答案中的所有贪婪的 .* 模式都会选择第一个&lt;url&gt; 和最后一个&lt;/url&gt; 上线。如果&lt;url&gt;&lt;/url&gt; 之间有换行符,则正则表达式将完全错过该条目。 XML 解析器可以避免所有这些问题。因此,请注意,正则表达式和 XML 或 HTML 通常不太适合。

标签: regex shell sed grep


【解决方案1】:

如果你的grep不支持-P(见ruakh's answer),你可以使用sed来做:

sed -n 's|.*<url>\(.*\)</url>.*|\1|p'

【讨论】:

  • 你能解释一下这里发生了什么吗?它就像一个魅力。不过不确定这里发生了什么。
  • -n 取消默认值sed 输出,然后每次匹配给定模式时,他都会打印括号内捕获的相应值。
  • 是的,只要你想要“grep 但只打印部分匹配”,sed -n 就是你的朋友。 -n 说“默认情况下不要打印出每一行”。 s|.*&lt;url&gt;\(.*\)&lt;/url&gt;.*|\1|p 说“将包含 'stuff' 的任何整行替换为 标签之间的内容,然后打印该行。”替换不会在不匹配的行上成功,所以只有那些行被打印,并且只有在它完成替换之后。
【解决方案2】:

如果您的grep 版本支持-P 标志(用于Perl 兼容的正则表达式),您可以使用lookaround

grep -Po '(?<=<url>).*(?=</url>)' file.txt

【讨论】:

    【解决方案3】:

    我会使用sed:

    sed -n 's%.*<url>\(.*\)</url>.*%\1%p'
    

    -n 选项关闭默认打印。替换命令匹配单行上的&lt;url&gt;&lt;/url&gt; 标记,捕获其间的内容并包括匹配中的前导和尾随材料。替换的是捕获的材料,p 表示打印。我在s%%% 中使用了% 而不是s///,因为/ 出现在正则表达式中。另一种方法是使用斜杠并用反斜杠转义正则表达式中的斜杠。

    Perl 也是可行且简单的:

    perl -n -e 'print if s%.*<url>(.*)</url>.*%\1%'
    

    -n 创建一个 REPL,但它默认不打印; print 只有在替换操作进行替换时才会触发。

    这个稍微复杂一点的 Perl 脚本可以正确处理一行中的多个 &lt;url&gt;...&lt;/url&gt; 条目:

    perl -n -e 'print "$1\n" while (s%.*?<url>(.*?)</url>%%)'
    

    它使用非贪婪的正则表达式 (.*?) 来避免吃太多信息。当替换操作检测并删除带有可选前置垃圾的&lt;url&gt;...&lt;/url&gt; 时,代码会在 URL 标记之间打印匹配的部分,后跟换行符。

    给定数据:

    xyz <url>/localhost/index1.html</url> pqr
    xyz <url>/localhost/index2.html</url> abc <url>/localhost/index3.html</url> pqr
    <url>/localhost/index4.html</url>
    <url>/localhost/index5.html</url><url>/localhost/index6.html</url>
    xyz <url>/localhost/index7.html</url> abc <url>/localhost/index3.html</url> xyz <url>/localhost/index9.html</url> abc <url>/localhost/index0.html</url> pqr
    

    最后一个 Perl 脚本产生:

    /localhost/index1.html
    /localhost/index2.html
    /localhost/index3.html
    /localhost/index4.html
    /localhost/index5.html
    /localhost/index6.html
    /localhost/index7.html
    /localhost/index3.html
    /localhost/index9.html
    /localhost/index0.html
    

    【讨论】:

      猜你喜欢
      • 2013-09-09
      • 2012-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-13
      • 2021-10-23
      • 1970-01-01
      • 2018-08-23
      相关资源
      最近更新 更多