Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

arrays

bash

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.

like image 962
user1129812 Avatar asked Feb 13 '23 16:02

user1129812


2 Answers

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.

like image 145
kojiro Avatar answered Feb 16 '23 04:02

kojiro


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")
like image 23
anubhava Avatar answered Feb 16 '23 05:02

anubhava