【问题标题】:Parsing json with awk/sed in bash to get key value pair在 bash 中使用 awk/sed 解析 json 以获取键值对
【发布时间】:2013-09-25 08:33:53
【问题描述】:

我已经阅读了 SO 的许多现有问题,但没有一个能回答我正在寻找的问题。我知道使用 sed/awk 在 bash 中解析 json 很困难,但我只需要在每条记录的键值对的整个列表中的每条记录中的几个键值对。我想这样做是因为它会更快,因为主 JSON 非常大,有数百万条记录。

JSON 格式如下:

{
    "documents":
    [
        {
            "title":"a",   //needed
            "description":"b",  //needed
            "id":"c",  //needed
            ....(some more:not useful)....
            "conversation":
            [
                {
                    "message":"",
                    "id":"d",   //not needed
                    .....(some more)....
                    "createDate":"e",   //not needed
                },
                ...(some more messages)....
            ],
            "createDate":"f",  //needed
            ....(many more labels).....
        }
    ],
    ....(some more global attributes)....
}

现在为此我需要标记为需要的属性,但它们的公共键使得通过简单的 sed/awk 获取它是一个问题。任何人都可以建议我们是否可以使用 sed/awk 来做到这一点。如果可能的话,我们将不胜感激。

P.S.:我知道jsawk,但我不想引入任何依赖,所以如果可能,请建议使用 sed/awk。

编辑:下面给出的格式的多个 extries(如在文档中我们有一个列表)

"title":"a",
"description":"b"
"id":"c"
"createDate":"f"

编辑:JSON 没有任何空格。它的格式是为了便于阅读。

【问题讨论】:

  • 为什么不使用python ?还是某种 json 解析器?
  • @iamauser 起初认为,他们做的比我需要的多得多。
  • @AmanDeepGautam 了解您在这些 json 解析器中需要什么比尝试使用 awk 或 sed 更容易。当值跨越多行时,麻烦就来了。顺便问一下,您可以为输出生成一个示例格式吗?
  • @konsolebox 我已将字段标记为needed。我需要那些键值对。
  • 是的,但它们不会在输出中重新格式化吗?

标签: json bash shell sed awk


【解决方案1】:

如果关键字符 [{}] 始终在每一行中被隔离,这将起作用:

#!/usr/bin/awk -f

function walk(level, end) {
    while (getline > 0) {
        if (level && $NF ~ end) {
            return
        } 
        if ($NF == "{") {
            walk(level + 1, "},?")
        } else if ($NF == "[") {
            walk(level + 1, "],?")
        } else if (level == 3 && match($0, /"(title|description|id|createDate)":"[^"]*"/)) {
            print substr($0, RSTART, RLENGTH)
        }
    }
}

BEGIN {
    walk(0)
    exit
}

输入:

{
"documents":
[
{
"title":"a",   //needed
"description":"b",  //needed
"id":"c",  //needed
....(some more:not useful)....
"conversation":
[
{
"message":"",
"id":"d",   //not needed
.....(some more)....
"createDate":"e",   //not needed
},
...(some more messages)....
],
"createDate":"f",  //needed
....(many more labels).....
}
],
....(some more global attributes)....
}

输出:

"title":"a"
"description":"b"
"id":"c"
"createDate":"f"

【讨论】:

    【解决方案2】:

    好吧,如果你打算使用正则表达式来解析 JSON,它本质上是快速、肮脏且严重依赖于输入文件的确切语法的,你可以编写一些依赖于空格数量的东西发生在您感兴趣的键值对之前。根据您要查找的输出类型,您可以使用以下内容:

    awk '/^ {12}"title/
    /^ {12}"description/
    /^ {12}"id/
    /^ {12}"createDate/' input_file.json
    

    不是很好,但它可以解决您的示例输入问题...

    【讨论】:

    • 不会给出所有的“createDate”标签吗?
    • 它只会匹配前面正好有 12 个空格的“createDate”标签。
    • 哦...我才意识到这一点。该示例已格式化以提高可读性。实际的 json 没有空格。很抱歉造成混乱。
    【解决方案3】:

    我建议您使用“jq”或真正的 JSON 解析器。您不能使用任意正则表达式“解析”JSON。你可以用 awk 破解一些东西,但是如果你的输入有一个你没有预料到的形式,那很容易被破坏。

    所以,答案是,引入一个廉价的依赖项(jq,或类似的工具),并围绕它编写脚本。除非您在路由器或嵌入式计算机中运行此脚本,否则您可以轻松安装 jq。

    【讨论】:

      猜你喜欢
      • 2018-03-31
      • 1970-01-01
      • 2012-12-11
      • 1970-01-01
      • 2013-02-06
      • 1970-01-01
      • 1970-01-01
      • 2015-01-12
      • 1970-01-01
      相关资源
      最近更新 更多