Reputation: 204638
How can I populate a bash array with multi-line command output?
For example given this printf command:
$ printf 'a\nb\n\nc\n\nd\ne\nf\n\n'
a
b
c
d
e
f
I would like to have a bash array populated as if I wrote:
$ arr[0]='a
b'
$ arr[1]='c'
$ arr[2]='d
e
f'
and so could loop through it as:
$ for i in "${arr[@]}"; do printf "<%s>\n" "$i"; done
<a
b>
<c>
<d
e
f>
I have tried various incarnations of using a NUL character to separate my intended array fields instead of a blank line as that seems like my best bet but no luck so far, e.g.:
$ IFS=$'\0' declare -a arr="( $(printf 'a\nb\n\0c\n\0d\ne\nf\n\0') )"
$ for i in "${arr[@]}"; do printf "<%s>\n" "$i"; done
<a>
<b>
<c>
<d>
<e>
<f>
I also tried mapfile -d $'\0'
but my mapfile doesn't support -d
.
I did find that this works:
$ declare -a arr="( $(printf '"a\nb" "c" "d\ne\nf"') )"
$ for i in "${arr[@]}"; do printf "<%s>\n" "$i"; done
<a
b>
<c>
<d
e
f>
but that seems a little clunky and I'd have to escape "
s when all I really want it to tell the shell to use some character other than a blank as the array fields separator.
Upvotes: 3
Views: 3395
Reputation: 295904
A best-practice approach, using NUL delimiters:
arr=( )
while IFS= read -r -d '' item; do
arr+=( "$item" )
done < <(printf 'a\nb\n\0c\n\0d\ne\nf\n\0')
...which would be even simpler with bash 4.4:
mapfile -t -d '' arr < <(printf 'a\nb\n\0c\n\0d\ne\nf\n\0')
Much more crudely, supporting the double-newline separator approach:
item=''
array=( )
while IFS= read -r line; do
if [[ $line ]]; then
if [[ $item ]]; then
item+=$'\n'"$line"
else
item="$line"
fi
else
[[ $item ]] && {
array+=( "$item" )
item=''
}
fi
done < <(printf 'a\nb\n\nc\n\nd\ne\nf\n\n')
Upvotes: 8