arraysbashindexingjqcontent-length

Problem with bash readarray -t array assignment when jq outputs an empty string


First - a very simple code:

#!/bin/bash

a_string="string"
readarray -t a <<<"$a_string"
echo "${a[@]}"
echo "${#a[@]}"

# read empty string into array
emptystring=""
readarray -t b <<<"$emptystring"
echo "${b[@]}"
echo "${#b[@]}"

# and now - empty array
c=()
echo "${c[@]}"
echo "${#c[@]}"

And the output

string
1

1

0

So reading an empty string into bash array with readarray -t shows array length as 1. And only truly empty array's length is 0.

My question - why it is happening?

As my case - here is a fragment from my script - execute an API call, get JSON, and apply jq filter:

URL_list_json=$(curl -s --request GET "$curl_request" --header "Authorization: Bearer ${token}")
readarray -t URL_names <<<"$(echo "$URL_list_json" | jq -r '.[].Body.monitors[].name')"

Here is an example of JSON which results an empty array from the jq call:

[
    {
        "Header": {
            "Region": "dc1",
            "Tenant": "tenant1",
            "Stage": "test"
        },
        "Body": {
            "monitors": []
        }
    }
]

and here is JSON with populated content returning a non-empty array from jq call:

[
    {
        "Header": {
            "Region": "dc2",
            "Tenant": "tenant2",
            "Stage": "qa"
        },
        "Body": {
            "monitors": [
                {
                    "enabled": true,
                    "entityId": "TEST-674BA97E74FC74AA",
                    "name": "production.example.com"
                },
                {
                    "enabled": false,
                    "entityId": "TEST-3E2D23438A973D1E",
                    "name": "test.example.com"
                }
            ]
        }
    }
]

I need to check if URL_names array is empty or not. If not empty, then iterate over contents. If empty - means that jq did not return any results - white to log and move on.

If I use if ((${#URL_names[@]})) as a means to check if the array is empty or not, it will return 1 even if the array has just an empty string from the jq call, so this logic fails.

What are alternative approaches to deal with the case like above?

I can assign the output of the jq filter to a string and then use if statement to check if the string is empty and if non-empty then assign the string to an array, but this introduces additional elements. With this approach, I can skip using arrays entirely - I was hoping to use only arrays for this task.

Thanks


Solution

  • why it is happening?

    Because it reads one line. From bash manual here document:

    [n]<<< word

    [...] The result is supplied as a single string, with a newline appended, to the command on its standard input (or file descriptor n if n is specified).

    Because there is a newline, readarray reads one empty line. You may do:

    readarray -t b < <(printf "%s" "$emptystring")
    

    Notes: