Numeric argument passed with jq --arg not matching data with ==

前端 未结 2 1648
一整个雨季
一整个雨季 2020-12-18 06:10

Here is a sample JSON response from my curl:

{
  \"success\": true,
  \"message\": \"jobStatus\",
  \"jobStatus\": [
    {
      \"ID\": 9,
      \"status\":         


        
相关标签:
2条回答
  • 2020-12-18 06:31

    jq is data-type-aware:

    • .ID, as defined in the JSON input, is a number,

    • but any command-line argument passed with --arg (such as v here) 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 2 may 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 2 is 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).
    • Therefore jq interprets --argjson -v 2 as a number, and comparison .ID == $v works as intended (note that the same applies to --argjson -v '2' / --argjson -v "2", where the shell removes the quotes before jq sees the value).
      By contrast, anything you pass with --arg is 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 strings true and false.


    Tip of the hat to peak for his help.

    0 讨论(0)
  • 2020-12-18 06:38

    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'
    
    0 讨论(0)
提交回复
热议问题