4

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.

0

3 Answers 3

6

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.

Sign up to request clarification or add additional context in comments.

2 Comments

readarray -t will discard the trailing newline from each line.
@chepner good catch. Now that I've logged into a system with bash 4 and actually read the help, I've updated my answer.
1

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")

Comments

1

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.

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.