将 json 文件转换为“key-path”,结果值位于每个“key-path”的末尾

Chr*_*ris 4 grep scripting bash json jq

我有一个较大且相对复杂的 json 配置文件,我想使用“grep”等简单工具搜索键和/或值。当我'grep'我希望在输出中包含的文件包含键的完整路径以及导致最终值的每个子键/数组时。

这类似于在大型文件系统中搜索文件/目录,并且在找到文件/目录时能够看到文件/目录的完整路径,例如使用“find”命令。

同样作为与我试图完成的类似比较的是 xml2 实用程序,它将 xml 文件转换为键/值路径,以便于搜索和报告。

我一直在使用 'jq' 实用程序使用 'keys' 命令解析 json 文件。我已经将一个粗略的 bash 脚本拖到了一起,以遍历 json 键路径的第一个分支——但找不到一种简单的方法来递归地遍历 json 结构的完整树。

这是我在 bash 脚本中尝试执行的操作的手动说明。是的,它的效率非常低,但我想我会在提高性能之前让它工作!

给定包含复杂配置的 file.json,我使用键来获取第一项,一旦我有了它,我就在另一个迭代中使用它来获取下一个键,依此类推,直到到达分支的末尾......

cat file.json | jq '. | keys | .[]'
cat file.json | jq '.Blueprints | keys | .[]'
cat file.json | jq '.Blueprints.security | keys | .[]'
cat file.json | jq '.Blueprints.security.kerberos_descriptor | keys | .[]'
cat file.json | jq '.Blueprints.security.kerberos_descriptor.identities | keys | .[]'
Run Code Online (Sandbox Code Playgroud)

最终的结果最终看起来是这样的:

."Blueprints"."security"."kerberos_descriptor"."identities"[0]."keytab"."configuration"."cluster-env/smokeuser_keytab"
Run Code Online (Sandbox Code Playgroud)

但当然,这只是非常大的键/值树的第一个分支。

Mic*_*mer 9

jq有一些合适的内置函数可以提供帮助。你不需要太多的 Bash 技巧,它不太适合解决这个问题。这是 jq 中的一个非常明确的版本,您应该能够根据需要进行修改:

jq -r '. as $root |
       path(..) | . as $path |
       $root | getpath($path) as $value |
       select($value | scalars) |
       ([$path[] | @json] | join(".")) + " = " + ($value | @json)
    ' < file.json
Run Code Online (Sandbox Code Playgroud)

它多次使用变量绑定运算符... as $identifier |来按名称记住计算值 - 其中一些是不必要的,但它们使讨论更容易。这些行中的每一行都将$x程序其余部分的变量绑定到左侧的值。

path/1函数是这里的关键,并且基本上已经完成了您想要的操作:path(..)生成一个包含您需要遍历以获取嵌套在对象中的每个值的所有键的数组。每条路径都是形式

[ "Blueprints", "security", "kerberos_descriptor" ]
Run Code Online (Sandbox Code Playgroud)

它们可以像其他数组一样使用,也可以与解释路径的特殊函数一起使用。

path(..) | . as $path |
Run Code Online (Sandbox Code Playgroud)

特别是定义一个循环:对于文件中的每个路径,调用它$path并将程序的其余部分作为循环体运行。程序的其余部分是选择和输出,因此对于每条路径,都会对其进行检查并可能生成输出行。

getpath读取这些路径数组之一并取出它标识的值。select让我们过滤到只通过测试的值 - 在这里,它只选择标量(数字、字符串、布尔值或空值)的值,因此中间对象和数组被排除在外(空值也是如此)。

最后一行将输出格式化为

"abc"."def".3."xyz" = true
Run Code Online (Sandbox Code Playgroud)

对于文件中的每个值,每行一个,您可以根据需要进行调整。将它重定向到一个文件中,您可以grep反复浏览它。

@json正确引用值,其余的应该很容易更改以适合您需要的格式。它不为数组使用方括号,因为手动复制join将点放入其他情况的功能非常复杂。两边都需要括号。