From the manual:
-e / --exit-status:
Sets the exit status of jq to 0 if the last output values was neither false nor null, 1 if the last output value was either false or null, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran.
So you can use:
if jq -e . >/dev/null 2>&1 <<<"$json_string"; then
echo "Parsed JSON successfully and got something other than false/null"
else
echo "Failed to parse JSON, or got false/null"
fi
In fact, if you don't care about distinguishing between the different types of error, then you can just lose the -e switch. In this case, anything considered to be valid JSON (including false/null) will be parsed successfully by the filter . and the program will terminate successfully, so the if branch will be followed.
From the manual:
-e / --exit-status:
Sets the exit status of jq to 0 if the last output values was neither false nor null, 1 if the last output value was either false or null, or 4 if no valid result was ever produced. Normally jq exits with 2 if there was any usage problem or system error, 3 if there was a jq program compile error, or 0 if the jq program ran.
So you can use:
if jq -e . >/dev/null 2>&1 <<<"$json_string"; then
echo "Parsed JSON successfully and got something other than false/null"
else
echo "Failed to parse JSON, or got false/null"
fi
In fact, if you don't care about distinguishing between the different types of error, then you can just lose the -e switch. In this case, anything considered to be valid JSON (including false/null) will be parsed successfully by the filter . and the program will terminate successfully, so the if branch will be followed.
This is working for me
echo $json_string | jq -e . >/dev/null 2>&1 | echo ${PIPESTATUS[1]}
that returns return code:
- 0 - Success
- 1 - Failed
- 4 - Invalid
Then you can evaluate the return code by further code.
Yes, JQ can do all that. Here is how I'd write it:
jq -nr '
def valid_key: test("^[A-Za-z_][0-9A-Za-z_]*$");
def valid_value:
type != "array" and type != "object" and (
type != "string" or (test("\u0000") | not)
);
def valid_input:
type == "object" and (
to_entries | all(
(.key | valid_key) and (.value | valid_value)
)
);
input |
if valid_input and isempty(inputs) then
to_entries[] | "\(.key)=\(.value | @sh)"
else
"bad input\n" | halt_error(1)
end'
Here's a demo how to do the testing. For production, however, it'd obviously need more refinement.
if type != "object" then "\(@json) is not an object (#1)"
else to_entries[] |
if .key | test("\\A[_a-zA-Z]\\w*\\z") | not then "\(.key | @json) is illegal (#2)"
else .value |
if isempty(scalars) then "\(.) is not a scalar (#3)"
else tostring |
if test("\u0000") then "\(.[index("\u0000")+1:] | @json) is preceded by NUL (#4)"
else empty
end
end
end
end // (to_entries[] | .key + "=" + (.value | @sh))
"" is illegal (#2)
"illegal key shall fail" is illegal (#2)
[1,2] is not a scalar (#3)
{"k":"v"} is not a scalar (#3)
".txt" is preceded by NUL (#4)
task_uuid='5d7ea654-b649-452b-a8fd-002b56be9a59'
task_name='hello world'
user_email=null
min=7
max=100
ave=2.5
file_in='data.txt'
file_out='results.txt'
Demo