jq -e always exits with status 0 when passed empty input. For example:
$ echo | jq --exit-status 'false'; echo $?
0
Consider a use case like this one:
call-some-json-api |
jq --exit-status '.field == "some-value"' &&
take-action
If the API call fails and output is only written to stderr, take-action will still run as though the call succeeded, and "some-value" had been set.
This may be related to issue #667, but that one has been fixed on master, and this bug is still present.
A minor (one line) change to my fix proposal (PR #1140) for related #1139 issue should fix this.
Simply change the default ret value to '4' would break --exit-status semantics,
(it would always return 4 in such a case, while it should return 0 if -e is not set)
Exactly, @rfletcher! With the current behavior of jq -e, the calling script is forced to either call the input command twice or saving the result in some intermediate buffer to avoid calling it a second time.
I ended up with a workaround like this in my script:
# Exit with failure code (1) if we have no input
# Otherwise jq will happily exit with 0 (https://github.com/stedolan/jq/issues/1142)
some_input_script &>/dev/null || exit 1
some_input_script | jq --exit-status ".$key == true" >/dev/null
There appears to be no way to handle or work around this with just a single jq filter/invocation — but there should be! (Even if we had to add another flag, like ~--empty-input-as-failure~ (or --empty-input-as-null, see #1628), that would be better than nothing.)
By the way, this issue came up again in #1497.
For anyone who (like me) comes across this trying to check whether a file is valid json, you can use one of these workarounds until the underlying jq issue is fixed:
To just check that filename.json is valid json:
[ -s filename.json ] && jq -e . filename.json && echo filename.json is valid || echo invalid json
To also check for the presence of a .foo key:
[ -s filename.json ] && jq -e .foo filename.json && echo filename.json contains .foo || echo nope
another workaround:
$ echo | jq -es 'if . == [] then null else .[] | your-pipe end'
$ echo $?
1
Most helpful comment
another workaround: