The bash runs every loop (while or for) in a subshell. The values for a variable defined inside such a loop / subshell are not available outside.
#!/bin/bash
t=0
while read line; do
t=$(( t + 1 ))
done < /etc/passwd
echo $t
Returns 0 for $t but inside the loop the value is right.
To use a variable outside a loop, just extend the subshell.
#!/bin/bash
t=0
cat /etc/passwd | { while read line; do
t=$(( t + 1 ))
done;
echo $t
}
The script shows the last value for $t inside the loop. The trick is { … } – the subshell runs in the defined area.
Sure, the example is not very useful. If you would just read a file and get the number of lines, wc -l
works also. But you can also execute the shells reverse:
t=0
while read line; do
t=$(( t + 1 ))
done < /etc/passwd
echo $t
$t is always 0.
Danke aus Russland!
(English follows)
I ran into same problem: two nested loops needed to communicate with each other. And I found that inner loop does not return anything into outer one.
I found a workaround: results were dumped into the temporary file, which was read in outer loop then. But it was slow and inconvenient. Your suggestion worked much better.
Scheinbar wird heute(2019, Bash 4.2.46) nicht mehr jeder loop in einer Subshell ausgeführt. Der erste Code funktioniert nämlich, t ist nicht 0. Nur bei dem Kontrukt “cat /etc/passwd | while read line” ohne die geschweifte Klammer gibt es das Verhalten noch.