Search code examples
bashjqnul

Storing JQ NULL-delimited output in bash array


on bash 4.4.12 using jq 1.5 with this one-liner IFS=_ read -r -a a < <(jq -ncj '["a","b","c"][]+"_"') ; printf '%s\n' "${a[@]}" I get a properly delimited output

a

b

c

for elements a, b and c respectively, BUT if I try the same thing with a null delimiter like so: IFS= read -r -a a < <(jq -ncj '["a","b","c"][]+"\u0000"') ; printf '%s\n' "${a[@]}" then I would get only one array element containing

abc

Why doesn't this work like expected?

Furthermore, if you try IFS= read -r -d '' -a a < <(jq -ncj '["a","b","c"][]+"\u0000"') ; printf '%s\n' "${a[@]}, you will be surprised to get an array with only the first "a" element:

a

My goal is to find an approach without iterating over elements with any kind of a loop.

Edit: **readarray -d** is not a solution since i need the piece of code to run in bash prior to version 4.4


Solution

  • Use readarray, which gained a -d analogous to the same option on read in bash 4.4:

    $ readarray -d $'\0' -t a < <(jq -ncj '["a","b","c"][]+"\u0000"')
    $ declare -p a
    declare -a a=([0]="a" [1]="b" [2]="c")
    

    -d '' works as well; since shell strings are null terminated, '' is, technically, the string containing the null character.


    Without readarray -d support, you can use a while loop with read, which should work in any version of bash:

    a=()
    while read -d '' -r item; do
        a+=("$item")
    done < <( jq -ncj '["a","b","c"][]+"\u0000"' )
    

    This is the best you can do unless you know something about the array elements that would let you pick an alternate delimiter that isn't part of any of the elements.