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.
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.
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")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With