【问题标题】:Using sed/awk to process a pattern in bash使用 sed/awk 处理 bash 中的模式
【发布时间】:2013-12-19 14:25:34
【问题描述】:

我有一个命令,其输出格式为:

[{"foo1":<some value>,"foo2":<some value>,"foo3":<some value>}]

我想获取这个命令的输出,只获取foo2对应的值 如何使用 sed/awk 或 bash 脚本中随时可用的任何其他 shell 实用程序来执行此操作?

【问题讨论】:

  • 你有不同的“:”内容的样本来定义可能的分隔符

标签: bash shell sed awk


【解决方案1】:

假设值不包含逗号,这个sed rune 会这样做:

sed -n 's/.*"foo2":\([^,]*\),.*/\1/'p

sed -n 告诉sed 默认不打印行。

s ("substitute") 命令使用由\( 和\) 分隔的正则表达式组来挑选您想要的位。

"foo2": 提供找到正确值所需的上下文。

[^,]* 表示“一个不是逗号的字符,任意次数”。这是你的 。如果值没有用逗号分隔,请更改它(以及分组括号后的逗号)以正确匹配。

.* 表示“任意字符,任意次数”,用于匹配你想要的位前后的所有字符。现在正则表达式将匹配整行。

\1 表示分组括号的内容。 sed 将用括号的内容替换与模式匹配的字符串(这是整行,因为我们在开头和结尾使用了 .*)。

最后,末尾的p 表示“打印结果行”。

【讨论】:

    【解决方案2】:

    以awk 为例:

    $ awk -F[:,] '{print $4}' file
    <some value2>
    
    • -F[:,] 将可能的字段分隔符设置为 : 或 ,。然后,就是计算foo2 的&lt;some value&gt; 所在位置的问题。正好是第四个。

    sed:

    $ sed 's/.*"foo2":\([^,]*\).*/\1/g' file
    <some value2>
    
    • .*"foo2":\([^,]*\).* 获取 foo2: 之后的字符串,直到逗号出现。然后它用\1 打印回来。

    【讨论】:

    • 如果在 ',"foo3"' 之前有一个 ',' 则不起作用,因此高度依赖于内容价值假设
    • 是的,awk 版本是真的。由于我们没有更多的样本数据,我假设没有。但是,sed 解决方案应该可以正确解决。
    • 同意,因为我还假设内容似乎是不包含的内容,例如单词或数字。如果需要,我要求提供内容样本以适应 sed
    【解决方案3】:

    您的数据块看起来像 JSON。 bash、sed 或 awk 中没有原生 JSON 解析,所以这里的所有答案要么建议你使用不同的、更合适的工具,要么它们会很老套,如果你的真实数据很容易失败看起来与您在此处提供的示例不同。

    也就是说,如果您确信您的 variable:value 块和行结构始终采用与本示例相同的格式,您也许可以自己编写(非常)仅适用于您的用例的基本解析器。

    请注意,您不能真正解析 sed 中的内容,它只是不是为此而设计的。如果您的数据看起来总是相同,则 sed 解决方案可能就足够了……但请记住,您只是模式匹配,而不是解析输入数据。已经有其他答案涵盖了这一点。

    对于出现在"foo2" 之后的冒号之后的字符串的非常简单的匹配,正如彼得建议的那样,您可以使用以下内容:

    $ data='[{"foo1":11,"foo2":222,"foo3":3333}]'
    $ echo "$data" | sed -ne 's/.*"foo2":\([^,]*\),.*/\1/p'
    

    正如我所说,这绝不应该与您的 JSON 的 解析 相混淆。对于abcde"foo2":bar,abcde 的输入字符串,它同样适用(或很差)。

    在 awk 中,您可以制作更高级的东西,但在 JSON 方面仍然存在严重限制。例如,如果您选择用逗号分隔字段,但随后在数据中的 &lt;some value&gt; 中放置了一个逗号,则 awk 不知道如何将其与字段分隔符区分开来。

    也就是说,如果您的 JSON 只有一层深度(即与您的示例数据匹配),那么以下方法可能适合您:

    $ data='[{"foo1":11,"foo2":222,"foo3":3333}]'
    $ echo "$data" | awk -F: -vRS=, '{gsub(/[^[:alnum:]]/,"",$1)} $1=="foo2" {print $2}'
    

    此 awk 脚本将逗号视为记录分隔符,将冒号视为字段分隔符。它不支持 JSON 中的任何深度级别,并且取决于字母数字变量名称。但它应该处理 JSON 拆分为多行。

    或者,如果您想避免丑陋的 hack,而 perl 或 python 解决方案不适合您,您可能想尝试 jsawk。有了它,你可能会使用这样的东西:

    $ data='[{"foo1":11,"foo2":222,"foo3":3333}]'
    $ echo "$data" | jsawk -a 'return this.foo2'
    [222]
    

    另请参阅:Parsing json with awk/sed in bash to get key value pair

    【讨论】:

      【解决方案4】:

      这对我有用。你可以试试这个

      echo "[{"foo1":<some value>,"foo2":<some value>,"foo3":<some value>}]" | awk -F"[:,]+" '{ if($3=="foo2") { print $4 }}'
      

      上面的 awk 使用了多个字段分隔符。我在这里使用了冒号和逗号

      【讨论】:

        【解决方案5】:

        因为这看起来像 JSON,让我们像 JSON 一样解析它:

        perl -MJSON -ne '$json = decode_json($_); print $json->[0]{foo2}, "\n"' <<END
        [{"foo1":"some value","foo2":"some, value","foo3":"some value"}]
        END
        
        some, value
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-10-23
          • 1970-01-01
          • 2013-08-17
          • 2021-07-19
          • 1970-01-01
          • 1970-01-01
          • 2018-03-31
          • 2019-02-20
          相关资源
          最近更新 更多