Here is a sample JSON response from my curl:
{
"success": true,
"message": "jobStatus",
"jobStatus": [
{
"ID": 9,
"status": "Successful"
},
{
"ID": 2,
"status": "Successful"
},
{
"ID": 99,
"status": "Failed"
}
]
}
I want to check the status of ID=2. Here is the command I tried:
cat test.txt|jq --arg v "2" '.jobStatus[]|select(.ID == $v)|.status'
response: there is none
I tried value 2 without quotes and still no result.
By contrast, if I try the command with a literal 2, it works:
cat test.txt | jq '.jobStatus[]|select(.ID == 2)|.status'
response:
"Successful"
I'm stuck. Can anyone help me identify the problem?
jq is data-type-aware:
.ID, as defined in the JSON input, is a number,but any command-line argument passed with
--arg(such asvhere) is invariably a string (whether you quote the value or not),
so, in order to compare them, you must use an explicit type conversion, such as with tonumber/1:
jq --arg v '2' '.jobStatus[] | select(.ID == ($v | tonumber)) | .status' test.txt
Given that you're only passing a scalar argument here, the following solution, using --argjson (jq v1.5+) is a bit of an overkill, but it is an alternative to explicit type conversion in that passing a JSON argument in effect passes typed data:
jq --argjson v '{ "ID": 2 }' '.jobStatus[] | select(.ID == $v.ID) | .status' test.txt
peak's answer demonstrates that even --argjson v 2 works (in which case comparing to $v works directly), which is certainly the most concise solution, but may require an explanation:
Even though
2may not look like JSON, it is: it is a valid JSON text containing a single value of type number (see json.org).- Specifically, it is the fact that
2is an unquoted token that starts with a digit that makes it a number in the context of JSON (the JSON string-value equivalent is"2", which from the shell would have to be passed as'"2"'- note the embedded double quotes).
- Specifically, it is the fact that
Therefore
jqinterprets--argjson -v 2as a number, and comparison.ID == $vworks as intended (note that the same applies to--argjson -v '2'/--argjson -v "2", where the shell removes the quotes beforejqsees the value).
By contrast, anything you pass with--argis always a string value that is used as-is.In other words:
--argjson, whose purpose is to accept arbitrary JSON texts as strings (such as'{ "ID": 2 }'in the example above), can also be used to pass number-string scalars to force their interpretation as numbers.
The same technique also works with Boolean stringstrueandfalse.
Tip of the hat to peak for his help.
Assuming you want to check for the JSON value 2, you have a choice to make - either convert the argument of --arg to a number, or use --argjson with a numeric argument. These alternatives are illustrated by the following:
jq --arg v 2 '.jobStatus[] | select(.ID == ($v|tonumber) | .status'
jq --argjson v 2 '.jobStatus[] | select(.ID == $v) | .status'
Note that --argjson requires a relatively recent version of jq.
Of course, if you want to "normalize" .ID so that it's always treated as a string, you could write:
jq --arg v 2 '.jobStatus[] | select((.ID|tostring) == $v) | .status'
来源:https://stackoverflow.com/questions/41772776/numeric-argument-passed-with-jq-arg-not-matching-data-with