Search code examples
jsonbashjqreturn-code

How can I tell if a jq filter successfully pulls data from a JSON data structure?


I want to know if a given filter succeeds in pulling data from a JSON data structure. For example:

###### For the user steve...

% Name=steve
% jq -j --arg Name "$Name" '.[]|select(.user == $Name)|.value' <<<'
[
   {"user":"steve", "value":false},
   {"user":"tom", "value":true},
   {"user":"pat", "value":null},
   {"user":"jane", "value":""}
]'
false
% echo $?
0

Note: successful results can include boolean values, null, and even the empty string.

###### Now for user not in the JSON data...

% Name=mary
% jq -j --arg Name "$Name" '.[]|select(.user == $Name)|.value' <<<'
[
   {"user":"steve", "value":false},
   {"user":"tom", "value":true},
   {"user":"pat", "value":null},
   {"user":"jane", "value":""}
]'
% echo $?
0

If the filter does not pull data from the JSON data structure, I need to know this. I would prefer the filter to return a non-zero return code.

How would I go about determining if a selector successfully pulls data from a JSON data structure vs. fails to pull data?

Important: The above filter is just an example, the solution needs to work for any jq filter.

Note: the evaluation environment is Bash 4.2+.


Solution

  • I've found a solution that meets all of my requirements! Please let me know what you think!

    The idea is use jq -e "$Filter" as a first-pass check. Then for the return code of 1, do a jq "path($Filter)" check. The latter will only succeed if, in fact, there is a path into the JSON data.

    Select.sh

    #!/bin/bash
    
    Select()
    {
       local Name="$1"
       local Filter="$2"
       local Input="$3"
       local Result Status
    
       Result="$(jq -e --arg Name "$Name" "$Filter" <<<"$Input")"
       Status=$?
    
       case $Status in
       1) jq --arg Name "$Name" "path($Filter)" <<<"$Input" >/dev/null 2>&1
          Status=$?
          ;;
       *) ;;
       esac
    
       [[ $Status -eq 0 ]] || Result="***ERROR***"
       echo "$Status $Result"
    }
    
    Filter='.[]|select(.user == $Name)|.value'
    Input='[
       {"user":"steve", "value":false},
       {"user":"tom", "value":true},
       {"user":"pat", "value":null},
       {"user":"jane", "value":""}
    ]'
    
    Select steve "$Filter" "$Input"
    Select tom   "$Filter" "$Input"
    Select pat   "$Filter" "$Input"
    Select jane  "$Filter" "$Input"
    Select mary  "$Filter" "$Input"
    

    And the execution of the above:

    % ./Select.sh
    0 false
    0 true
    0 null
    0 ""
    4 ***ERROR***