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
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:
echo "$var"
is not preferred. Do printf "%s" "$var"
when in posix shell, do <<<"$var"
when in bash (and you do not care about the extra newline).<<<"$(...)"
always looks strange - the <<<
has to allocate a subshell anyway. Do < <(...)
.readarray -t URL_names < <(<<<"$URL_list_json" jq -r '.[].Body.monitors[].name')
jq
. I see ex. jq --exit-status '.[].Body.monitors[].name'
and just check the exit status.