In der Bash wird jeder loop (while oder for) in einer Subshell gestartet. Die Werte einer Variable sind außerhalb der Subshell nicht verfügbar.
#!/bin/bash
t=0
while read line; do
t=$(( t + 1 ))
done < /etc/passwd
echo $t
Gibt für $t 0 aus. Wird $t innerhalb von while ausgegeben, stimmt der Wert.
Um die Variable auch nach der Subshell (hier while-loop) zur Verfügung zu haben, muss die Subshell nur erweitert werden.
#!/bin/bash
t=0
cat /etc/passwd | { while read line; do
t=$(( t + 1 ))
done;
echo $t
}
Hier ist der Wert für $t 0. Der Trick ist { … } – die Subshell läuft komplett im defnierten Bereich.
Zugegeben, dass Beispiel ist nicht besonders glücklich, da man das ganze beim Auslesen einer Datei nur umdrehen muss (oder schlicht wc -l
nutzt), um die Variable der Subshell zu behalten. Das Prinzip zeigt sich daran aber sehr gut.
Umgedreht sieht das nämlich so aus:
t=0
while read line; do
t=$(( t + 1 ))
done < /etc/passwd
echo $t
Auch hier ist $t 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.