I'm wondering why this code is not working as expected:
a=(1)
echo "1 2 3 4" | while read f; do
a+=("$f")
done
echo "${a[@]}"
Output is "1" and not "1 1 2 3 4" as I thought it would be. Any ideas?
I'm wondering why this code is not working as expected:
a=(1)
echo "1 2 3 4" | while read f; do
a+=("$f")
done
echo "${a[@]}"
Output is "1" and not "1 1 2 3 4" as I thought it would be. Any ideas?
If you create a pipe, you create a sub shell. The a
array is correct modified, but only in the sub shell which exits before you print the contents of a
after the loop.
Solution, use process substitution or a here string instead of a pipe:
a=(1)
# this only loops once since there is only one line...
while read f; do
a+=("$f")
done < <(echo "1 2 3 4") # < <(process substitution)
echo "${a[@]}"
# 1 1 2 3 4
As a side note, use declare -p a
instead of echo "${a[@]}"
to see the contents of an array in Bash if you also want to see the indices.
Here is a better example of what you are seeing:
#!/bin/bash
lines=("Top")
echo "Line 1
Line 2
Line 3" | while read -r line; do
lines+=("$line")
declare -p lines
done
declare -p lines
Prints:
declare -a lines=([0]="Top" [1]="Line 1")
declare -a lines=([0]="Top" [1]="Line 1" [2]="Line 2")
declare -a lines=([0]="Top" [1]="Line 1" [2]="Line 2" [3]="Line 3")
declare -a lines=([0]="Top")
Note that lines
reverts to only one entry after the pipeline. Vs:
lines=("Top")
while read -r line; do
lines+=("$line")
declare -p lines
done < <(echo "Line 1
Line 2
Line 3")
declare -p lines
Prints:
declare -a lines=([0]="Top" [1]="Line 1")
declare -a lines=([0]="Top" [1]="Line 1" [2]="Line 2")
declare -a lines=([0]="Top" [1]="Line 1" [2]="Line 2" [3]="Line 3")
declare -a lines=([0]="Top" [1]="Line 1" [2]="Line 2" [3]="Line 3")