9

I have something like this:

FILES=()
for i in *.map
do
    FILES+=($i)
done

find /var/candy -name "chocolate_[0-9]" | while read snack
do
    FILES+=($snack)
done

for file in ../out/amsterdam/apples/{system.map,vmlinux}
do
    FILES+=($file)
done

But the array ends up only containing ../out/amsterdam/apples/system.map and ../out/amsterdam/apples/vmlinux. What happened to the other values? I know they exist in those loops because I echoed to make sure the variables contained something.

0
15

Taken from the Bash FAQ:

I set variables in a loop that's in a pipeline. Why do they disappear after the loop terminates?

The reason for this potentially surprising behaviour, as described above, is that each SubShell introduces a new variable context and environment. The while loop above is executed in a new subshell with its own copy of the variable linecount created with the initial value of '0' taken from the parent shell. This copy then is used for counting. When the while loop is finished, the subshell copy is discarded, and the original variable linecount of the parent (whose value hasn't changed) is used in the echo command.

To avoid a subshell from being created in your second loop, you can feed data to it in ways other than through a pipe:

while read snack; do
    FILES+=($snack)
done < <(find /var/candy -name "chocolate_[0-9]")

.

while read snack; do
    FILES+=($snack)
done <<<"$(find /var/candy -name "chocolate_[0-9]")"
2
  • What about if I have a function like append() { FILES+=$1 ; } and then for each loop do for i in (whatever); do append $i ; done – Gregg Leventhal Nov 8 '13 at 19:03
  • The example in your comment above works. Remember that the problem you encountered is present only in the second loop, which contains the pipe. I'll update my answer. – Teresa e Junior Nov 8 '13 at 20:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.