为什么在 'jq' 中向过滤器添加括号会产生有效的 JSON 而没有括号会产生多个对象输出?
Why is adding parentheses to a filter in 'jq' producing valid JSON and without parentheses, multiple outputs of objects?
使用 jq, I would like to set a property within JSON data and let jq 输出带有更新值的原始 JSON。由于反复试验,我或多或少找到了一个解决方案,并且想了解它的工作原理和工作原理。
我有以下 JSON 数据:
{
"notifications": [
{
"source": "observer01",
"channel": "error",
"time": "2021-01-01 01:01:01"
},
{
"source": "observer01",
"channel": "info",
"time": "2021-02-02 02:02:02"
}
]
}
我的目标是用特定的 source
和 channel
更新对象的 time
属性(原来的 JSON 更长notifications
数组中有很多相同格式的对象)。
(在下面的例子中,我想用通道info
更新observer01
的time
属性,所以上面例子数据中的第二个对象。 )
我的第一次尝试是以下 jq
命令,但没有产生所需的输出:
jq '.notifications[] | select(.source == "observer01" and .channel == "info").time = "NEWTIME"' data.json
产生以下输出:
{
"source": "observer01",
"channel": "error",
"time": "2021-01-01 01:01:01"
},
{
"source": "observer01",
"channel": "info",
"time": "NEWTIME"
}
这只是 notifications
数组中 JSON 个对象的列表。我知道这很有用,例如将对象通过管道传输到其他命令行工具。
现在让我们试试下面的jq
命令,它和上面一样加上一对括号:
jq '(.notifications[] | select(.source == "observer01" and .channel == "info").time) = "NEWTIME"' data.json
这会产生所需的输出,原始有效 JSON 和更新后的 time
属性:
{
"notifications": [
{
"source": "observer01",
"channel": "error",
"time": "2021-01-01 01:01:01"
},
{
"source": "observer01",
"channel": "info",
"time": "NEWTIME"
}
]
}
为什么在上述情况下将括号添加到 jq
过滤器会产生不同的输出?
括号只是改变了优先级。它记录在 man jq
:
Parenthesis work as a grouping operator just as in any typical programming language.
jq ´(. + 2) * 5´
1
=> 15
让我们举一个更简单的例子:
echo '[{"a":1}, {"a":2}]' | jq '.[] | .a |= .+1'
输出
{
"a": 2
}
{
"a": 3
}
因为它被解释为
↓ ↓
echo '[{"a":1}, {"a":2}]' | jq '.[] | (.a |= .+1)'
第一个过滤器 .[]
将元素作为分离的对象输出,然后由第二个过滤器修改。
在前两个元素之后放置括号会更改优先级:
↓ ↓
echo '[{"a":1}, {"a":2}]' | jq '(.[] | .a) |= .+1'
并产生不同的输出:
[
{
"a": 2
},
{
"a": 3
}
]
顺便说一句,这与 from
的输出相同
echo '[{"a":1}, {"a":2}]' | jq '.[].a |= .+1'
它更改与数组中的 "a"
键关联的值。
让我们比较一下两者。
.notifications[] | select(...).time = "NEWTIME"
(.notifications[] | select(...).time) = "NEWTIME"
在第一个中,顶级过滤器由 |
定义。输入是一个对象,输出是将 select(...).time = "NEWTIME"
应用于 .notifications[]
产生的每个值的结果。本质上,原来的对象“丢失”了。
在第二个中,顶级过滤器由 =
定义。 x = y
returns 其输入作为输出,但具有
产生的副作用
- 确定路径表达式
x
在输入中指的是什么,
- 在输入上评估 过滤器
y
,(即使像 "NEWTIME"
这样的表达式也只是一个过滤器:忽略其输入和 returns 字符串 "NEWTIME"
)
- 正在将
y
的结果分配给 x
所处理的事物。
使用 jq, I would like to set a property within JSON data and let jq 输出带有更新值的原始 JSON。由于反复试验,我或多或少找到了一个解决方案,并且想了解它的工作原理和工作原理。
我有以下 JSON 数据:
{
"notifications": [
{
"source": "observer01",
"channel": "error",
"time": "2021-01-01 01:01:01"
},
{
"source": "observer01",
"channel": "info",
"time": "2021-02-02 02:02:02"
}
]
}
我的目标是用特定的 source
和 channel
更新对象的 time
属性(原来的 JSON 更长notifications
数组中有很多相同格式的对象)。
(在下面的例子中,我想用通道info
更新observer01
的time
属性,所以上面例子数据中的第二个对象。 )
我的第一次尝试是以下 jq
命令,但没有产生所需的输出:
jq '.notifications[] | select(.source == "observer01" and .channel == "info").time = "NEWTIME"' data.json
产生以下输出:
{
"source": "observer01",
"channel": "error",
"time": "2021-01-01 01:01:01"
},
{
"source": "observer01",
"channel": "info",
"time": "NEWTIME"
}
这只是 notifications
数组中 JSON 个对象的列表。我知道这很有用,例如将对象通过管道传输到其他命令行工具。
现在让我们试试下面的jq
命令,它和上面一样加上一对括号:
jq '(.notifications[] | select(.source == "observer01" and .channel == "info").time) = "NEWTIME"' data.json
这会产生所需的输出,原始有效 JSON 和更新后的 time
属性:
{
"notifications": [
{
"source": "observer01",
"channel": "error",
"time": "2021-01-01 01:01:01"
},
{
"source": "observer01",
"channel": "info",
"time": "NEWTIME"
}
]
}
为什么在上述情况下将括号添加到 jq
过滤器会产生不同的输出?
括号只是改变了优先级。它记录在 man jq
:
Parenthesis work as a grouping operator just as in any typical programming language.
jq ´(. + 2) * 5´ 1 => 15
让我们举一个更简单的例子:
echo '[{"a":1}, {"a":2}]' | jq '.[] | .a |= .+1'
输出
{
"a": 2
}
{
"a": 3
}
因为它被解释为
↓ ↓
echo '[{"a":1}, {"a":2}]' | jq '.[] | (.a |= .+1)'
第一个过滤器 .[]
将元素作为分离的对象输出,然后由第二个过滤器修改。
在前两个元素之后放置括号会更改优先级:
↓ ↓
echo '[{"a":1}, {"a":2}]' | jq '(.[] | .a) |= .+1'
并产生不同的输出:
[
{
"a": 2
},
{
"a": 3
}
]
顺便说一句,这与 from
的输出相同echo '[{"a":1}, {"a":2}]' | jq '.[].a |= .+1'
它更改与数组中的 "a"
键关联的值。
让我们比较一下两者。
.notifications[] | select(...).time = "NEWTIME"
(.notifications[] | select(...).time) = "NEWTIME"
在第一个中,顶级过滤器由 |
定义。输入是一个对象,输出是将 select(...).time = "NEWTIME"
应用于 .notifications[]
产生的每个值的结果。本质上,原来的对象“丢失”了。
在第二个中,顶级过滤器由 =
定义。 x = y
returns 其输入作为输出,但具有
- 确定路径表达式
x
在输入中指的是什么, - 在输入上评估 过滤器
y
,(即使像"NEWTIME"
这样的表达式也只是一个过滤器:忽略其输入和 returns 字符串"NEWTIME"
) - 正在将
y
的结果分配给x
所处理的事物。