Consider this example, say, test.sh:
cat > test.txt <<'EOF'
test 1
test 2
test 3
EOF
declare -a myarr
declare -p myarr # "declare: myarr: not found"
myarr=()
declare -p myarr # "declare -a myarr='()'"
#for (( i=1; i<=3; i++ )); do # ok
sed -n 's!test!TEST!p' test.txt | while read i; do # not preserved ?!
myarr=("${myarr[@]}" "pass $i")
declare -p myarr
done
declare -p myarr # "declare -a myarr='()'" ?!
If I uncomment the for ((... line, and comment the sed -n ... line, then the output of bash test.sh is as expected:
test.sh: line 8: declare: myarr: not found
declare -a myarr='()'
declare -a myarr='([0]="pass 1")'
declare -a myarr='([0]="pass 1" [1]="pass 2")'
declare -a myarr='([0]="pass 1" [1]="pass 2" [2]="pass 3")'
declare -a myarr='([0]="pass 1" [1]="pass 2" [2]="pass 3")'
However, if I run the script as posted, then the myarr builds in the while loop, but once outside, it's empty:
test.sh: line 8: declare: myarr: not found
declare -a myarr='()'
declare -a myarr='([0]="pass TEST 1")'
declare -a myarr='([0]="pass TEST 1" [1]="pass TEST 2")'
declare -a myarr='([0]="pass TEST 1" [1]="pass TEST 2" [2]="pass TEST 3")'
declare -a myarr='()'
So, why is myarr in this case (in, or rather, after the while loop) empty - and how do I get it to preserve its value?
Problem is that due to use of pipeline, you are forking a subshell and populating entries in your array inside the subshell. Once your loop ends, subshell terminates and all the changes get lost there.
You can use a process substitution to avoid this:
myarr=()
while IFS= read -r line; do
myarr+=("pass $line")
done < <(sed -n 's!test!TEST!p' test.txt)
# examine the result
declare -p myarr
Output:
declare -a myarr=([0]="pass TEST 1" [1]="pass TEST 2" [2]="pass TEST 3")
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