Reputation: 2889
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
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
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
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