Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can it be determined if a jq selector succeeds or fails, given null or false might be a valid result?

Tags:

bash

jq

For a given selector to jq, I want to know if the selector succeeds or fails given its input. For example, the following correctly indicates an error status:

% jq -re .bad <<<'{}'
null
% echo $?
1
%

However, the following incorrectly indicates an error status (as far as my needs go):

% jq -re .key <<<'{"key":false}'
false
% echo $?
1
%

The problem with the above is that the -e option will give a return status of 1 if the last output value was either false or null. However, if values of false and null are present in the JSON input, then this return status gives the wrong impression that some failure occurred.

Am I compelled, in the case of a return code 1, to then check to see if the key is present? For example:

#!/bin/bash

Result=$(jq -re .key <<<'{"key":false}')
Status=$?
if [[ $Status -eq 1 ]] ; then
   jq -re '. | has("key")' <<<'{"key":false}' && (exit 0) || (exit 1)
else
   (exit $Status)
fi

# At this point $? can be relied on to indicate success/failure

The above solution would change the return status of 1 to 0 and is acceptable for simple jq selectors, but this solution is not satisfactory for computational selectors that might generate a valid result of false or null.

So, is there any approach to know whether a jq selector really succeeds or fails (even for computational selectors), considering that results such as false and null may be either valid or invalid depending on the selector and input

The solution should be done in Bash 4.2 or later.

like image 369
Steve Amerige Avatar asked Nov 22 '25 10:11

Steve Amerige


2 Answers

I think this filter will work:

map(select(.user==$Name and .value==true))[0] or error($Name)

Example:

#!/bin/bash
for i in steve tom mary; do
    echo '[{"user":"steve", "value":false},{"user":"tom", "value":true}]' \
    | jq -M -r --arg Name $i 'map(select(.user==$Name and .value==true))[0] or error($Name)' 
    echo $i $?
done

Output:

jq: error (at <stdin>:1): steve
steve 5
true
tom 0
jq: error (at <stdin>:1): mary
mary 5

So in the case of steve and mary jq returns non-zero exit status and in the case of tom it returns zero exit status.

like image 96
jq170727 Avatar answered Nov 24 '25 04:11

jq170727


It is not entirely clear to me what it is you are trying to do, but I have the impression that you are going about it the wrong way. Part of the problem may be the result of terminological issues. To avoid them, I will adopt terminology that is appropriate to JSON and jq.

Let me point out firstly that in jq, expressions such as {} | .a are not regarded as erroneous. If you want an error condition to be raised when an attempt to access the value of a non-existent key is made, you could write something like:

if has("a") then .a else error("no such key") end

Another way to distinguish between the case when an input object has a key and the case when it does not have the key is to write something like:

if has("a") then .a else empty end

or more compactly:

select(has("a")) | .a

You can use this technique in conjunction with the -c option of jq as illustrated by the following bash assignments:

result=$(jq -c 'select(has("a")) | .a' INPUT.json)
n=$(wc -l <<< "$result")

You can then check the value of $n.

like image 44
peak Avatar answered Nov 24 '25 02:11

peak



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!