On Sat, Nov 27, 2004 at 03:23:49PM +0100, Frank Benkstein wrote:
<code> echo "1" | read x ; echo $x echo "4" | { read x; } ; echo $x
Zwischen diesen beiden gibt es keinen semantischen unterschied. Geschweifte klammern werden zur Gruppierung verwendet. Da hier bei 4 nur ein Befehl zwischen den Klammern steht gibt es auch nichts zu gruppieren.
echo "2" | ( read x; echo $x; ) echo "3" | { read x; echo $x; }
</code>
Hier wird korrekt gruppiert.
Das Problem ist, dass eine Pipe immer eine Subshell fork()t, d.h fuer den 1. und 4. Fall, dass das "read x" in einer Subshell ausgefuehrt wird. Diese Subshell hat aber keine Moeglichkeit der Vatershell zu sagen, welchen Wert $x nun hat. (Nach dem ; beendet sich die Subshell wieder). Im 2. und 3. Fall fuehrt aber die Subshell das "echo $x" aus. Im 2. Fall werden womoeglich sogar 2 Subshells gestartet, eine durch die Pipe, die andere durch die runden Klammern.
Haeufig stoesst man bei while-read-Schleifen auf das Problem.
dmesg | while read f do x="$f" done echo $x;
Die while-Schleife wird in diesem Fall in der Subshell ausgefuehrt, und kann folglich das $x des Vaterprozesses nicht setzen. Loesung in diesem Fall sind named pipes.
FIFO=/tmp/fifo.$$ mkfifo $FIFO
dmesg > $FIFO & while read f x="$f" done < $FIFO rm $FIFO echo $x
Der Trick ist, das Kommando vor der Pipe in einer Subshell auszufuehren.
Ich hoffe das war halbwegs verstaendlich.
/GM