然而努力用 jq 解析 JSON

Yet struggling to parse JSON with jq

我正在慢慢掌握 jq 的工作原理,但离掌握它还有很长的路要走。 现在我处于一种情况,我有点设法得到我想要的东西,但没有按照我想要的方式显示它。我确定它很简单,但我想念它...

这是我要解析的 JSON 的示例:

{
    "sites": [
        {
            "site_id": 123456,
            "status": "configured",
            "domain": "www.domain.com",
            "account_id": 654321,
            "security": {
                "waf": {
                    "rules": [
                        {
                            "action": "block_request",
                            "action_text": "Block",
                            "id": "sqli",
                            "name": "SQLi"
                        },
                        {
                            "action": "block_request",
                            "action_text": "Block",
                            "id": "xss",
                            "name": "XSS"
                        },
                        {
                            "action": "alert",
                            "action_text": "Alert",
                            "id": "path_vector",
                            "name": "Path Vector"
                        }
                    ]
                }
            }
        }
    ],
    "res": 0,
    "res_message": "OK",
    "debug_info": {
        "id-info": "9123"
    }
}

我只需要一些细节并将它们放入 CSV 格式,这是我目前所做的:

cat test.json | jq -r '.sites [] | [.site_id,.domain],(.security.waf.rules[] | [.action_text]) | @csv'

这是我得到的输出:

123456,"www.domain.com"
"Block"
"Block"
"Alert"

还不错,但我正在寻找的是这样的东西:

123456,"www.domain.com","Block","Block","Alert"

相同的结果,只是显示在一行中。 我浏览了手册页并摆弄了一段时间无济于事。 是否可以这样做,或者我需要一个不同的工具来操纵它?

提前致谢!

要在 CSV 行中打印的所有值必须收集在 JSON 数组中。因此,与您的尝试非常相似的解决方案是:

.sites[]
| [.site_id, .domain, (.security.waf.rules[] | .action_text) ]
| @csv

对了,不用cat:

jq -r -f program.jq test.json

首先让我们讨论一下您收到该结果的原因。

当您使用 [] 从 objects/arrays 中提取项目时,它会为 object/array 中的每个项目生成一个值。

.sites[]

sites 数组中的每个值生成一个结果(在本例中只有一个)。

还有一点需要注意,使用逗号 (,) 将在该表达式中产生分隔值。

[.site_id,.domain]

这里的逗号产生两个值,site_iddomain。但是,这些值被收集到一个数组中(如方括号所示)。

将其放入表达式的下一部分

.security.waf.rules[] | [.action_text]

第一部分遍历该数组中的所有规则对象。然后为每个对象创建一个包含 action_text 的数组。这将创建三个数组(每个规则一个)。

将其与表达式的前一部分放在一起(稍微重新格式化)

([.site_id,.domain]) , (.security.waf.rules[] | [.action_text])

这一切一起产生四个数组,包含 site_iddomain 的数组,然后是 action_text.

的三个数组

然后,对于这四个数组中的每一个,都会创建一个 csv 行,为您提供您看到的结果。


那么怎样才能得到想要的结果呢?

首先,我们要开始浏览所有站点。我假设您想要每个站点一行。

.sites[]

然后,对于每个站点,我们需要构建该行中值的数组。从我们可以直接访问的内容开始。

.site_id, .domain

然后生成 action_text 个值。

.security.waf.rules[].action_text

请注意,我们没有将 action_text 放在单独的数组中,我们只需要值。

现在我们将这些值放在一起。

.site_id, .domain, (.security.waf.rules[].action_text)

正如我们所讨论的那样,这会创建五个值,但我们希望将它们收集在一个数组中,以便我们可以将其传递给 @csv 过滤器。

[.site_id, .domain, (.security.waf.rules[].action_text)]

把所有东西放在一起会得到这个过滤器:

.sites[] | [.site_id, .domain, (.security.waf.rules[].action_text)] | @csv

当然,您可以采用多种方法来获取这些值(例如分别构建数组然后组合它们),但这是最直接的方法。