我正在编写一个Bash函数来获取JSON对象的一部分。该函数的API是:
GetSubobject()
{
local Filter="$1" # Filter is of the form .<key>.<key> ... .<key>
local File="$2" # File is the JSON to get the subobject
# Code to get subobject using jq
# ...
}
为了说明子对象的含义,请考虑Bash函数调用:
GetSubobject .b.x.y example.json
文件example.json包含的位置:
{
"a": { "p": 1, "q": 2 },
"b":
{
"x":
{
"y": { "j": true, "k": [1,2,3] },
"z": [4,5,6]
}
}
}
函数调用的结果将发送到stdout:
{
"y": {
"j": true,
"k": [
1,
2,
3
]
}
}
请注意,代码jq -r "$Filter" "$File"
不会给出所需的答案。它会给:
{ "j": true, "k": [1,2,3] }
请注意,我正在寻找的答案需要是我可以在上面的Bash函数API中使用的。因此,答案应该使用上面显示的过滤器和文件变量,而不是特定于上面的示例。
我想出了一个解决方案;但是,它依靠Bash来完成部分工作。我希望解决方案可以是纯jq而不依赖于Bash处理。
#!/bin/bash
GetSubobject()
{
local Filter="$1"
local File="$2"
# General case: separate:
# .<key1>.<key2> ... .<keyN-1>.<keyN>
# into:
# Prefix=.<key1>.<key2> ... .<keyN-1>
# Suffix=<keyN>
local Suffix="${Filter##*.}"
local Prefix="${Filter%.$Suffix}"
# Edge case: where Filter = .<key>
# Set:
# Prefix=.
# Suffix=<key>
if [[ -z $Prefix ]]; then
Prefix='.'
Suffix="${Filter#.}"
fi
jq -r "$Prefix|to_entries|map(select(.key==\"$Suffix\"))|from_entries" "$File"
}
GetSubobject "$@"
我如何使用jq完成上述Bash功能以获得所需的结果,希望以较少暴力的方式利用jq的功能而无需在Bash中进行预处理?
有点进一步简化jq
部分,但与JawguyChooser的答案具有相同的一般约束,如何更简单的Bash函数
GetSubject () {
local newroot=${1##*.}
jq -r "{$newroot: $1}" "$2"
}
我可能会忽略更复杂的Bash处理的一些细微差别,但这似乎适用于您提供的示例。
如果我理解你正在努力做的事情,我似乎不可能在阅读文档时做“纯jq”(并且我自己也是常规的jq
用户)。我能在这里帮助最接近的是简化jq
部分本身:
jq -r "$Prefix| { $Suffix }" "$File"
这与您的示例具有相同的行为(在这组有限的情况下):
GetSubobject '.b.x.y' example.json
{
"y": {
"j": true,
"k": [
1,
2,
3
]
}
}
这实际上是一个元编程的例子,你想以编程方式运行jq
程序。好吧,对我而言,jq
将其程序作为输入是有意义的,但不允许你改变程序本身。 bash似乎是在这里进行元编程的合适选择:将jq
程序转换为另一个程序,然后使用它运行jq
。
如果目标是在bash
尽可能少地做,那么可能以下bash函数将填写账单:
function GetSubobject {
local Filter="$1" # Filter is of the form .<key>.<key> ... .<key>
local File="$2" # File is the JSON to get the subobject
jq '(null|path('"$Filter"')) as $path
| {($path[-1]): '"$Filter"'}' "$File"
}
另一种方法是将$Filter
作为字符串传递(例如--arg过滤器“$ Filter”),让jq进行解析,然后使用getpath
。
如果可以通过将路径与感兴趣的字段分开来调用GetSubobject,这当然是最简单的,如下所示:
GetSubobject .b.x y filename