【问题标题】:grep: group capturinggrep:组捕获
【发布时间】:2012-01-26 00:48:53
【问题描述】:

我有以下字符串:

{"_id":"scheme_version","_rev":"4-cad1842a7646b4497066e09c3788e724","scheme_version":1234}

我需要获取“方案版本”的值,在本例中为 1234。

我试过了

grep -Eo "\"scheme_version\":(\w*)"

然而它返回

"scheme_version":1234

我怎样才能做到?我知道我可以添加 sed 调用,但我更喜欢使用单个 grep。

【问题讨论】:

  • 我认为仅使用 'grep' 是不可能的。几年前,我在字符串操作方面做了很多工作,经常将 grep 传递给诸如“sed”或“cut”之类的东西。我建议你学习“管道”和“剪切”命令。
  • 我不经常使用 grep,但也许您可以使用后向表达式,如stackoverflow.com/questions/1247812/… 中接受的答案中所述。
  • 使用jq

标签: regex linux bash grep


【解决方案1】:

改进@potong 的答案,仅用于获取“scheme_version”,您可以使用此表达式:

$ echo '{"_id":"scheme_version","_rev":"4-cad1842a7646b4497066e09c3788e724","scheme_version":1234}' | sed -n 's/.*"_id":["]*\([^(",})]*\)[",}].*/\1/p'
scheme_version

$ echo '{"_id":"scheme_version","_rev":"4-cad1842a7646b4497066e09c3788e724","scheme_version":1234}' | sed -n 's/.*"_rev":["]*\([^(",})]*\)[",}].*/\1/p'
4-cad1842a7646b4497066e09c3788e724

$ echo '{"_id":"scheme_version","_rev":"4-cad1842a7646b4497066e09c3788e724","scheme_version":1234}' | sed -n 's/.*"scheme_version":["]*\([^(",})]*\)[",}].*/\1/p'
1234

【讨论】:

    【解决方案2】:

    为避免使用GNU grep 中提供但BSD version 中没有的greps PCRE 功能,另一种方法是使用ripgrep,例如

    $ rg -o 'scheme_version.?:(\d+)' -r '$1' <file.json 
    1234
    

    -r 捕获组索引(例如,$5)和名称(例如,$foo)。

    另一个使用 Python 和 json.tool module 的示例可以验证和漂亮打印:

    $ python -mjson.tool file.json | rg -o 'scheme_version[^\d]+(\d+)' -r '$1'
    1234
    

    相关:Can grep output only specified groupings that match?

    【讨论】:

      【解决方案3】:

      作为 SiegeX 建议的正向后视方法的替代方法,您可以使用 \K 转义序列将匹配起点直接重置为 scheme_version": 之后。例如,

      $ grep -Po 'scheme_version":\K[0-9]+'
      

      这会在匹配scheme_version": 后重新启动匹配过程,并且往往比正向回溯具有更好的性能。在 regexp101 上比较两者可以看出,reset match start 方法需要 37 步和 1ms,而正向lookbehind 方法需要 194 步和 21ms。

      您可以在regex101 上自己比较表现,您可以在PCRE documentation 中阅读更多关于重置比赛起点的信息。

      【讨论】:

        【解决方案4】:

        你可以这样做:

        $ echo '{"_id":"scheme_version","_rev":"4-cad1842a7646b4497066e09c3788e724","scheme_version":1234}' | awk -F ':' '{print $4}' | tr -d '}'
        

        【讨论】:

        • 虽然此代码块可能会回答 OP 的问题,但如果您解释此代码与问题中的代码有何不同、您所做的更改、您为什么更改了它以及为什么在不引入其他人的情况下解决了问题。
        【解决方案5】:

        我建议您使用jq 来完成这项工作。 jq 是一个命令行 JSON 处理器。

        $ cat tmp
        {"_id":"scheme_version","_rev":"4-cad1842a7646b4497066e09c3788e724","scheme_version":1234}
        
        $ cat tmp | jq .scheme_version
        1234
        

        【讨论】:

        • 在不了解 jq 的情况下,我是如何在生活中发挥作用的。哇。谢谢!
        【解决方案6】:

        这可能对你有用:

        echo '{"_id":"scheme_version","_rev":"4-cad1842a7646b4497066e09c3788e724","scheme_version":1234}' |
        sed -n 's/.*"scheme_version":\([^}]*\)}/\1/p'
        1234
        

        抱歉,它不是 grep,所以如果你愿意,请忽略此解决方案。

        或者坚持使用 grep 并添加:

        grep -Eo "\"scheme_version\":(\w*)"| cut -d: -f2
        

        【讨论】:

        • 看来这对我来说是最好的选择。
        • 您好,感谢您的回答。非常适合获取“scheme_version”值,但不能获取“_id”值。这个 sed 表达式对我有用,我正在回答:sed -n 's/.*"scheme_version":["]*\([^(",})]*\)[",}].*/\1/p'
        【解决方案7】:

        您需要使用断言后面的查找,以便它不包含在匹配中:

        grep -Po '(?&lt;=scheme_version":)[0-9]+'

        【讨论】:

        • 嗯,我得到了 grep:对 -P 选项的支持未编译到此 --disable-perl-regexp 二进制文件中
        • @Stipa 如果没有 PCRE 支持,您将无法使用 grep 做您想做的事情,因为它不支持反向引用,即 \1
        • 正是所要求的,起到了“积极向后看”的魅力
        • 对于我们这些有幸拥有-P 支持已经编译(或顽固地重建 grep...)的人来说,比公认的答案要好得多:)
        • 当您有多个命名组时,每个组都会在新行中输出。有没有办法在同一行打印它?例如cat ~/mydoc | grep -Po '(?&lt;=blah"&gt;)[^&lt;]*|(?&lt;=bleh"&gt;&lt;/span&gt;)[^&lt;]*' 在不同的行中打印捕获。
        猜你喜欢
        • 2010-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-11
        • 2013-02-14
        • 2018-01-15
        • 1970-01-01
        相关资源
        最近更新 更多