I’m trying to understand the behavior of jq pipes when using parentheses and commas. Let’s consider this JSON example:
{
"menu": [
{
"id": "file",
"value": "File",
"menuitem": [
{
"value": "New",
"onclick": "CreateNewDoc()"
},
{
"value": "Close",
"onclick": "CloseDoc()"
}
]
},
{
"id": "photo",
"value": "Photo",
"menuitem": [
{
"value": "New",
"onclick": "CreateNewDoc()"
},
{
"value": "Open",
"onclick": "OpenDoc()"
}
]
}
]
}
First, let’s apply a simple filter:
jq '.menu[].menuitem[] | .value'
Output:
"New"
"Close"
"New"
"Open"
This output is as expected.
Now, let’s add a compound filter separated by a comma and group the first filter using parentheses:
jq '(.menu[].menuitem[] | .value), . | {}'
Output:
{}
{}
{}
{}
{}
It looks like second pipe is working with output of first filters
Question: why?
According to the jq documentation:
If two filters are separated by a comma, then the same input will be fed into both and the two filters’ output value streams will be concatenated in order: first, all of the outputs produced by the left expression, and then all of the outputs produced by the right.
Following this logic, I would expect the output to be:
"New" // output of first filter
"Close"
"New"
"Open"
{} // output of second filter
However, this is not the case.
Corrected Filter
The filter works as expected if we add parentheses to the second filter:
jq '(.menu[].menuitem[] | .value), (. | {})'
Output:
"New"
"Close"
"New"
"Open"
{}
Main question
Why does the pipe (|
) operator seemingly ignore the parentheses and comma in the first compound filter? What is the logic behind this behavior?
0
|
isn’t “ignoring” anything. The problem seems to be that you’re expecting jq’s precedence to be different from what it is — ,
binds tighter than |
.
(.menu[].menuitem[] | .value), .
produces the same four values as your first sample, followed by the top-level input (.
), so that’s five outputs.
Then you pipe that into {}
, which is a filter that discards its input and produces an empty object. Since it gets five inputs, it produces five empty objects.
If you want grouping different from the default, you can get it using parentheses, as you already figured out.
Or, a simpler way to write the same filter would be .menu[].menuitem[].value, {}
. There’s no need to write . | {}
at all.
0