Search code examples
bashwso2-api-managerjqbackticks

jq script with back tick in JSON value


I'm using jq inside a bash script, to parse a JSON returned by an API REST service

This is my code (getting .count value)

# getAPIId
# Parse the answer of query API to get the API ID (checking version name)
# return (echo to stdout) the APIID
function getAPIId() {
    local apiId
    local version
    local -i count          

    if [ -z $1 ]
    then
        echo "Use: getAPIId \$apiQuery" >&2
        exit 1
    else    
        # Parse answer to API info
        count=$(echo "$1"|jq -r '.count')
        if [ "$count" == "0" ]
        then
            echo $1 >&2
            echo "ERROR: Cannot find an API called ${APINAME}" >&2
            return 1
        else
            for ((i=0; i<count; i++))
            do
                version=$(echo $1|jq -r '.list['$i'].version')
                if [ "$APIVERSION" == "$version" ] && [ "$APINAME" == "$name" ]
                then
                    apiId=$(echo $1|jq -r '.list['$i'].id')
                    echo "$apiId"
                    return 0
                fi
            done
        fi
    fi
    return 1

}

This is the JSON file I try to parse

{"count":1,"next":"","previous":"","list":[{"id":"6d2822e5-a90d-4738-b7b7-ef7d7848cb48","name":"SwaggerPetstore",
"description":"`special key`","context":"/v2","version":"1.0.0","provider":"admin","status":"CREATED","thumbnailUri":null}],"pagination":{"total":1,"offset":0,"limit":25}}

As you see, the field description contains back tick value. In this case, jq fails and return empty string (as not found value for count)

How can avoid the problem with backtick?


Solution

  • jq does not have any problem at all with backticks in literal values. You can see that as follows:

    $ jq '.value' <<<'{"otherKey": "`otherValue`", "value": "desired value `with backticks`"}'
    "desired value `with backticks`"
    

    With respect to the code given in the question, though, it's vastly overcomplicated. Rather than muddle through what could be wrong, consider the following replacement (which doesn't need to read count at all, and calls jq only once):

    # Aside: Using all-caps names is bad practice. Don't do this.
    APINAME=SwaggerPetstore
    APIVERSION=1.0.0
    
    getAPIId() {
      [[ $1 ]] || { echo 'Usage: getAPIId "$json"' >&2; return 1; }
      jq -er \
           --arg target_name "$APINAME" \
           --arg target_version "$APIVERSION" '
        .list[] |
        select(.name == $target_name) |
        select(.version == $target_version) |
        .id' <<<"$1"
    }
    

    ...returns, when called as follows:

    s='{
      "count": 1,
      "next": "",
      "previous": "",
      "list": [
        {
          "id": "6d2822e5-a90d-4738-b7b7-ef7d7848cb48",
          "name": "SwaggerPetstore",
          "description": "`special key`",
          "context": "/v2",
          "version": "1.0.0",
          "provider": "admin",
          "status": "CREATED",
          "thumbnailUri": null
        }
      ],
      "pagination": {
        "total": 1,
        "offset": 0,
        "limit": 25
      }
    }'
    
    getAPIId "$s"; echo "Exit status is $?" >&2
    

    ...the correct result of:

    6d2822e5-a90d-4738-b7b7-ef7d7848cb48
    Exit status is 0
    

    ...whereas if we run it again with an invalid name or version to search for:

    APINAME=NotFound getAPIId "$s"; echo "Exit status is $?" >&2
    

    ...correctly reflects that:

    Exit status is 4