user1129812
user1129812

Reputation: 2889

Error in reading a multi-line string into an array?

I am using the following bash codes to want to read a multi-line string into an array. I want each array element corresponds to one line of the string.

mytext="line one
line two
line three"
IFS=$'\n' read -a lines <<<"${mytext}"
echo "len=${#lines[@]}"
for line in "${lines[@]}"
do
   echo "[$line]"
done

I expect "len" should be equal to 3 and the "lines" array should be properly initialized. However, I got the following result :

len=1
[line one]

Have I used the wrong "IFS" ? What are the mistakes in the bash codes ? Thanks in advance.

Upvotes: 4

Views: 228

Answers (3)

kojiro
kojiro

Reputation: 77059

What's wrong with your solution is that read always reads a single line at a time, so telling it the IFS is a newline will make it read the entire line into the first element of the array. Each time you read you'll still overwrite the entire array. You can either build up the array iteratively:

lines=()
while read; do
  lines+=("$REPLY")
done <<< "$mytext"

or by swapping the newlines for something else:

IFS='+' read -a lines <<< "${mytext//$'\n'/+}"
$ IFS=@
$ echo "${lines[*]}"
line one@line two@line three

Using mapfile (a.k.a. readarray) would be a more coherent, elegant solution, but that's only supported in Bash 4:

mapfile -t lines <<< "$mytext"

$ printf '[%s]\n' "${lines[@]}"
[line one]
[line two]
[line three]

Without the -t flag, mapfile will keep the newline attached to the array element.

Upvotes: 6

anishsane
anishsane

Reputation: 20970

Not sure what is wrong in your case, but here is a workaround:

a=0
while read lines[$a]; do
    ((a++))
done <<< "${mytext}"
unset lines[$a]; #last iteration has already failed. Unset that index.

Upvotes: 1

anubhava
anubhava

Reputation: 784918

This while loop should work:

arr=()
while read -r line; do
   arr+=("$line")
done <<< "$mytext"

set | grep arr
arr=([0]="line one" [1]="line two" [2]="line three")

Upvotes: 1

Related Questions