【问题标题】:bash - print regex captured groupsbash - 打印正则表达式捕获的组
【发布时间】:2021-02-24 18:22:25
【问题描述】:

我有一个 file.xml 如此组成:

...some xml text here...
    <Version>1.0.13-alpha</Version>
...some xml text here...

我需要提取以下信息:

  • mayor_and_minor_release_number --> 1.0
  • patch_number --> 13
  • 后缀 --> -alpha

我认为最简洁的方法是使用带有 grep 命令的正则表达式:

<Version>(\d+\.\d+)\.(\d+)([\w-]+)?<\/Version>

我检查了regex101 这个正则表达式的正确性,实际上它似乎正确地捕获了我正在寻找的 3 个字段。但是问题来了,因为我不知道如何打印这些字段。

cat file.xml | grep "<Version>(\d+\.\d+)\.(\d+)([\w-]+)?<\/Version>" -oP

这个命令打印整行,所以没什么用。

这个网站上已经写了几篇关于这个主题的帖子,所以我也尝试使用 bash 原生 正则表达式支持,结果很差:

regex="<Version>(\d+\.\d+)\.(\d+)([\w-]+)?<\/Version>"
txt=$(cat file.xml)
[[ "$txt" =~ $regex ]]     --> it fails!
echo "${BASH_REMATCH[*]}"

很抱歉,我不知道如何解决这个问题。期望的输出应该是:

1.0
13
-alpha

【问题讨论】:

  • @Shawn 是的,你是对的。我忘了提到我不能使用纯 bash 以外的任何工具
  • stackoverflow.com/questions/8268138/… 可能会有所帮助。
  • 用户再次请求正则表达式帮助,regex 标签被删除。我正在再次恢复它,但这对 SO 不利。
  • @LéaGris 一般来说,你是对的。但是,在我看来,解析整个 xml 文件中的单个标签并不是 bash 无法完成的任务

标签: regex linux bash grep pattern-matching


【解决方案1】:

使用这个 Perl 单行代码:

perl -lne 'print for m{<Version>(\d+\.\d+)\.(\d+)([\w-]+)?<\/Version>};' file.xml

例子:

echo '<Version>1.0.13-alpha</Version>' | perl -lne 'print for m{<Version>(\d+\.\d+)\.(\d+)([\w-]+)?<\/Version>};'

输出:

1.0
13
-alpha

Perl 单行代码使用这些命令行标志:
-e:告诉 Perl 查找内联代码,而不是在文件中。
-n:循环输入一行一次,默认将其分配给 $_
-l :在执行内联代码之前剥离输入行分隔符(默认为 *NIX 上的 "\n"),并在打印时附加它。

另请参阅:
perldoc perlrun: how to execute the Perl interpreter: command line switches

【讨论】:

    【解决方案2】:

    您可以使用此read + sed 解决方案,其正则表达式与您的类似:

    read -r major minor suffix < <(
    sed -nE 's~.*<Version>([0-9]+\.[0-9]+)\.([0-9]+)(-[^<]*)</Version>.*~\1 \2 \3~p' file.xml
    )
    

    检查变量内容:

    declare -p major minor suffix
    
    declare -- major="1.0"
    declare -- minor="13"
    declare -- suffix="-alpha"
    

    几点:

    • grep 中不使用-P (perl) 模式就不能使用\d
    • grep 命令不返回捕获组

    【讨论】:

    • 它就像一个魅力。谢谢。我对sed知之甚少。但是,我想知道仅使用 RE_MATCHES 是否可以达到相同的结果。
    • 如果不使用\d,我们可以在bash 中使用&lt;Version&gt;([0-9]+\.[0-9]+)\.([0-9]+)(-[^&lt;]*)&lt;/Version&gt; 作为正则表达式,并在"${BASH_REMATCH[@]}" 中获取捕获的组,但bash 正则表达式更适合匹配字符串。如果我们试图在文件中找到匹配项,那么我们需要在循环中匹配或读取字符串中的完整文件,例如data="$(&lt;file.xml)"
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2018-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多