select 在数组或对象中

select within either array or object

鉴于这三个文件...

一个有语句对象:

{
    "PolicyVersion": {
        "CreateDate": "2017-07-13T18:59:21Z", 
        "VersionId": "v2", 
        "Document": {
            "Version": "2012-10-17", 
            "Statement": {
                "Action": "*", 
                "Resource": "*", 
                "Effect": "Allow"
            }
        }, 
        "IsDefaultVersion": true
    }
}

...还有一个带有语句数组:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

...还有一个声明嵌套在整个文档中:

{
    "PolicyVersion": {
        "CreateDate": "2017-07-13T18:59:21Z", 
        "VersionId": "v2", 
        "Document": {
            "Version": "2012-10-17", 
            "Statement": [
                {
                    "Action": "*", 
                    "Resource": "*", 
                    "Effect": "Allow"
                }
            ]
        }, 
        "IsDefaultVersion": true
    }
}

当语句中存在 .Action == '*'.Resource == '*' 时,是否可以对 select 使用单个命令,无论它是数组、对象还是嵌套位置?

例如,我正在扫描数千个文档,其中唯一的区别是 Statement 可能是对象或数组。

当然是这样的:jq '.PolicyVersion.Document.Statement[] | select((.Action == "*") and .Resource == "*")适用于数组,jq '.PolicyVersion.Document.Statement | select((.Action == "*") and .Resource == "*")适用于不是数组的情况,但我想在一个命令中实现。

我围绕 select 尝试了一些方法,例如:

jq '.PolicyVersion.Document | select((.Statement[] | select((.Action == "*") and .Resource == "*") or select((.Statement[] | select((.Action == "*") and .Resource == "*")'

其中 returns 没有,并且:

jq '.PolicyVersion.Document | select((.Statement[] | select((.Action == "*") and .Resource == "*") or select((.Statement | select((.Action == "*") and .Resource == "*")'

其中 returns 一个 unix shell 引用错误。

以下内容可能比您需要的更通用,或者可能过于通用,所以请随意调味:

..
| objects
| select(.Statement)
| .Statement
| if type == "array" then .[] else . end
| select(.Action == "*" and .Resource == "*")

另一种针对这种特殊情况的方法:

.PolicyVersion.Document.Statement
| ..
| select(type == "object" and .Action == "*" and .Resource == "*")

在 OP 的允许下,让我在这里展示如何使用 walk-path unix 实用程序 jtc 实现相同的 JSON 查询。但是,我不会解释 walk-path,而是展示如何构建它。

我对这个问题的理解:验证 JSON 文档,这样如果文档中的任何地方都有一个带有标签 Statement 的条目,其中包含元素 "Action": "*""Resource": "*" ,然后打印包含这些元素的整个记录​​,否则不要打印(即留下空白输出)

1。让我们从以递归方式查找带有标签 Statement 的 JSON 条目开始(递归搜索的表示法是 <..>,后缀 l 指示搜索 labels),因此它可以在 JSON 文档中的任何位置(我将使用第一个 JSON 示例):

bash $ <file.json jtc -w'<Statement>l'
[
   {
      "Action": "*",
      "Effect": "Allow",
      "Resource": "*"
   }
]
bash $ 

2。找到 Statement 记录后,我们需要查看找到的条目 中某处是否有记录 "*" 附加 到标签 "Action"(再次使用递归搜索,但将搜索仅限于带有 Action 标签的条目 - a.k.a。 范围搜索 ):

bash $ <file.json jtc -w'<Statement>l[Action]:<*>'
"*"
bash $ 

3。现在我们需要查看找到的条目是否有兄弟 ("Resource": "*")。为此,让我们在 JSON 树中更上一层楼(a.k.a 地址 parent):

bash $ <file.json jtc -w'<Statement>l[Action]:<*>[-1]'
{
   "Action": "*",
   "Effect": "Allow",
   "Resource": "*"
}
bash $

然后使用 non-recursive 范围搜索(non-recursive 搜索符号是 >..<):

bash $ <file.json jtc -w'<Statement>l[Action]:<*>[-1][Resource]:>*<'
"*"
bash $ 

4。最后,对于 select 记录,让我们再次解决最后一个 found/walked 条目的 parent:

bash $ <file.json jtc -w'<Statement>l[Action]:<*>[-1][Resource]:>*<[-1]'
{
   "Action": "*",
   "Effect": "Allow",
   "Resource": "*"
}
bash $ 

上面的walk-path将方便JSON查询所有JSON文档(无论Statement是否嵌套,或者 ActionResource 记录是否(深度)记录在数组中 - 但它们必须保持兄弟姐妹)。
如果任何一个 walk lexemes 失败,那么整个输出将是空白的:

bash $ <file.json jtc -w'<Statement>l[Action]:<blah>[-1][Resource]:>*<[-1]' 
bash $ 

最后,jtc 从文件读取时(而不是 stdin)快几倍,出于性能原因,最好使用它传递文件作为参数:

jtc -w'<Statement>l[Action]:<*>[-1][Resource]:>*<[-1]' file.json 

PS> 我是 jtc unix 实用程序的创建者,用于 JSON 处理