3

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.

1
  • 1
    FYI, mapfile in bash 4.4 supports -d and was released today. Commented Sep 17, 2016 at 0:50

1 Answer 1

8

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')
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.