#!/bin/bash
tmp="hallo welt"
ps aux | grep "/dev/" | while read line; do
tmp="$tmp $line"
# echo "tmp= $tmp"
done
echo "tmp= $tmp"
Ausgabe des Programms ist "tmp= Hallo Welt", wenn man den Kommentar
entfernt sieht man aber, dass die Variable "tmp" ordentlich gefüllt war.
Hmpf?
Bernd
--
Visit http://www.nixwill.de and http://www.spammichvoll.de
jean....@nixwill.de & bernado....@spammichvoll.de
> Offensichtlich verwendet auch die Bash eine temporäre Variable, die bei
> Beendigung der Loop verschwindet.
> Dieses Verhalten finde ich etwas lästig.
> Ich habe aber noch keine zufriedenstellende Lösung dafür gefunden.
> Meist kann man aber mit einem Würgaround leben.
Das scheint was mit der Pipe zu tun zu haben, die in meinem Muster
genutzt wird. Im Netz gibts hinreichend viele Diskussionen darüber, wie
man das umgehen kann - keine hat mir sonderlich gefallen was die
Lesbarkeit angeht.
Darum habe ich jetzt die Keule ausgepackt und schiebe die
Zwischenergebnisse in eine temporäre Datei - fertsch.
> Ernest Herder schrieb:
>
>> Offensichtlich verwendet auch die Bash eine temporäre Variable,
>> die bei Beendigung der Loop verschwindet.
>> Dieses Verhalten finde ich etwas lästig.
>> Ich habe aber noch keine zufriedenstellende Lösung dafür gefunden.
>> Meist kann man aber mit einem Würgaround leben.
>
> Das scheint was mit der Pipe zu tun zu haben, die in meinem Muster
> genutzt wird.
Nein:
var=foo; for text in bar fubar; do var="${var} ${text}"; done;
echo $var
foo bar fubar
Es liegt an der Pipeline. Das sind drei Prozesse, also naturgemäß
getrennte Environments. Die Lösung Deines Problems ist einfach:
"tmp= $(ps aux | grep "/dev/" | while read line; do
tmp="$tmp $line";done)"
CU
while...do macht eine Subshell. Nach done ist $tmp dieser Subshell
verloren und du hast nur noch das $tmp von oben.
man export
Juergen
--
Juergen P. Meier - "This World is about to be Destroyed!"
end
If you think technology can solve your problems you don't understand
technology and you don't understand your problems. (Bruce Schneier)
Bernd Hohmann <bernd.hohma...@freihaendler.com> wrote:
> Ich werde alt... sowas funktionierte doch sonst so schön?
>
> #!/bin/bash
> tmp="hallo welt"
> ps aux | grep "/dev/" | while read line; do
> tmp="$tmp $line"
> # echo "tmp= $tmp"
> done
> echo "tmp= $tmp"
>
> Ausgabe des Programms ist "tmp= Hallo Welt", wenn man den Kommentar
> entfernt sieht man aber, dass die Variable "tmp" ordentlich gefüllt war.
> Hmpf?
Beide Seiten der Pipeline laufen in ihrer eigenen Subshell. Die Subshell
fuer die rechte Seite der pipeline, in der du fleissig Variablen setzt,
wird nach Beendigung dieser Kommandozeile beendet und deine Aenderungen
am Environment sind damit verloren ...
Tschuess,
Juergen Ilse (jue...@usenet-verwaltung.de)
--
Ein Domainname (auch wenn er Teil einer Mailadresse ist) ist nur ein Name,
nicht mehr und nicht weniger ...
Du meintest am 06.11.09:
>> Ich werde alt... sowas funktionierte doch sonst so sch�n?
>>
>> #!/bin/bash
>> tmp="hallo welt"
>> ps aux | grep "/dev/" | while read line; do
>> tmp="$tmp $line"
>> # echo "tmp= $tmp"
>> done
>> echo "tmp= $tmp"
>>
>> Ausgabe des Programms ist "tmp= Hallo Welt", wenn man den Kommentar
>> entfernt sieht man aber, dass die Variable "tmp" ordentlich gef�llt
>> war.
> while...do macht eine Subshell. Nach done ist $tmp dieser Subshell
> verloren und du hast nur noch das $tmp von oben.
> man export
"export" ist interessant zu lesen (allerdings wohl besser "help
export"), l�st aber das Problem nicht:
#! /bin/bash
tempo=drei
export tempo
(echo vorher $tempo
tempo=vier
echo drinnen $tempo
)
echo nachher $tempo
#
zeigt, dass "tempo" in der Subshell eher als lokale Variable behandelt
wird, insbesondere wird der in der Subshell zugewiesene Wert nicht
zur�ckgegeben.
Viele Gruesse
Helmut
"Ubuntu" - an African word, meaning "Slackware is too hard for me".
> while...do macht eine Subshell.
Nein:
var=foo; while true; do var=geändert; break; done; echo $var
geändert
Die Pipeline macht die Subshell.
Hallo,
> #!/bin/bash
> tmp="hallo welt"
> ps aux | grep "/dev/" | while read line; do
> tmp="$tmp $line"
> # echo "tmp= $tmp"
> done
> echo "tmp= $tmp"
>
> Ausgabe des Programms ist "tmp= Hallo Welt", wenn man den Kommentar
> entfernt sieht man aber, dass die Variable "tmp" ordentlich gef�llt
> war.
Dass deine Schleife in einer Subshell ausgef�hrt wird, wurde ja bereits
erkl�rt. Ich l�se so etwas meistens per "Here-Document":
tmp="hallo welt"
while read line
do
tmp="$tmp $line"
done <<EOF
$(ps aux | grep "/dev/")
EOF
echo "tmp= $tmp"
Gru�
J�rg
>Bernd Hohmann <bernd.hohma...@freihaendler.com> writes:
>Dass deine Schleife in einer Subshell ausgef�hrt wird
Und _warum_ ist das so?
WO ist der (shell-interne) Zwang begr�ndet, das eine:
(irgendwas was in einer Pipe abgeht) | while read VAR
do
# tu was
done
anders zu behandeln als:
while read VAR
do
# tu was
done < (das selbe wie oben nur paedagogisch schlechter plaziert :-)
Warum ueberhalt eine Sub-Shell?
fragend, Holger
> Und _warum_ ist das so?
Also wenn wir schon bei Wünsch-Dir-was sind, dann möchte ich gerne
per Prozessflag (a la zsh) angeben können, welches Pipeline-Element
im Originalkontext der Pipeline ausgeführt wird, denn es ist ja
nicht gottgegeben, dass immer das letzte Element das entscheidende
sein muss.
> Joerg Mertens <joerg-...@t-online.de> writes:
>
>>Bernd Hohmann <bernd.hohma...@freihaendler.com> writes:
>
>>Dass deine Schleife in einer Subshell ausgef�hrt wird
>
> Und _warum_ ist das so?
Das liegt vermutlich daran, dass die einzelnen Elemente einer Pipeline
parallel ausgef�hrt werden. Es m�ssen also mehrere Prozesse erzeugt
werden, die dementsprechend auch alle eine eigene Umgebung haben. Die
Subshell erbt zwar zun�chst die Umgebung der Original-Shell, aber sie
kann �ber die Umgebungsvariablen nichts zur�ckgeben -- wenn die Subshell
beendet ist, sind die Daten weg.
J�rg
Pipe hei�t Parallelausf�hrung. Parallelausf�hrung hei�t neuer Prozess.
Neuer Prozess f�r einen internen Befehl hei�t Subshell.
Bei der Umleitung aus einer Datei bzw. einem Here-Document gibt es keine
Parallelausf�hrung. Damit wird auch keine Subshell ben�tigt.
Stefan
> Bei der Umleitung aus einer Datei bzw. einem Here-Document gibt es keine
> Parallelausf�hrung. Damit wird auch keine Subshell ben�tigt.
Beim Here-Document gibt es schon Parallelausf�hrung, sonst w�rde das
hier nicht funktionieren:
while read line
do
echo "-> $line"
done <<EOF
$(yes)
EOF
Die While-Schleife l�uft sofort los, obwohl "yes" unendlich viele Zeilen
produziert.
Mit dem folgenden Bash-Feature hingegen geht es beispielsweise nicht,
weil die Schleife auf das Ende der Befehlssubstitution warten muss,
"yes" jedoch nie terminiert.
while read line
do
echo "-> $line"
done <<< $(yes)
Gru�
J�rg
Holger Petersen <h...@kbbs.org> wrote:
> Joerg Mertens <joerg-...@t-online.de> writes:
>>Dass deine Schleife in einer Subshell ausgeführt wird
> Und _warum_ ist das so?
Weil die shell nicht multitasking-faehig ist, das darunterliegende System
aber schon: Wenn nun beide Teile der pipeline parallel ausgefuehrt werden
sollen, muss jeder Teil in einem eigenen Prozess laufen, also geht das
nicht in nur einer shell ...
Das funktioniert ja auch nicht. Jedenfalls bei mir (bash auf Linux bzw.
Cygwin). '$(yes)' ergibt ja erstmal einen String, und bis der nicht
fertig ist, l�uft 'while' nicht los.
Ich will nicht ausschlie�en, dass es Shells gibt, die da "optimieren",
aber drauf verlassen w�rde ich mich nicht.
> Mit dem folgenden Bash-Feature hingegen geht es beispielsweise nicht,
> weil die Schleife auf das Ende der Befehlssubstitution warten muss,
> "yes" jedoch nie terminiert.
>
> while read line
> do
> echo "-> $line"
> done <<< $(yes)
Das ist nur eine Abk�rzung f�r normale Here-Documents und benimmt sich
daher im Wesentlichen genauso.
Was funktioniert, wenn die Shell das unterst�tzt, ist
while read line; do
echo "-> $line"
done < <(yes)
Hier legt die Shell eine (named) pipe an, an deren Schreiber-Ende 'yes'
steht, und ersetzt '<(yes)' durch den Namen der Pipe. Damit ist das
ganze syntaktisch wieder eine normale Eingabeumleitung.
Stefan
>>>Dass deine Schleife in einer Subshell ausgef�hrt wird
>> Und _warum_ ist das so?
>
> Weil die shell nicht multitasking-faehig ist, das darunterliegende System
> aber schon: Wenn nun beide Teile der pipeline parallel ausgefuehrt werden
> sollen, muss jeder Teil in einem eigenen Prozess laufen [...]
Ein Element einer Pipeline kann durchaus im aktuellen Environment
ausgef�hrt werden. ksh88 und ksh93 machen das so - mit dem letzten
Element. Und manchmal ist genau das wohl n�tzlich. Traditionell
ist's aber eben nicht vorhanden.
> Joerg Mertens wrote:
>> Beim Here-Document gibt es schon Parallelausf�hrung, sonst w�rde das
>> hier nicht funktionieren:
>>
>> while read line
>> do
>> echo "-> $line"
>> done <<EOF
>> $(yes)
>> EOF
>
> Das funktioniert ja auch nicht. Jedenfalls bei mir (bash auf Linux bzw.
> Cygwin). '$(yes)' ergibt ja erstmal einen String, und bis der nicht
> fertig ist, l�uft 'while' nicht los.
Du hast Recht, da bin ich wohl mit den Shells durcheinandergekommen. In
bash funktionieren beide Versionen nicht.
> Ich will nicht ausschlie�en, dass es Shells gibt, die da "optimieren",
> aber drauf verlassen w�rde ich mich nicht.
Einigen wir uns auf "Beim Here-Document kann es je nach Shell
Parallelausf�hrung geben". Mit /bin/sh unter NetBSD ist das zum
Beispiel der Fall. Mit der ksh wiederum nicht.
>> Mit dem folgenden Bash-Feature hingegen geht es beispielsweise nicht,
>> weil die Schleife auf das Ende der Befehlssubstitution warten muss,
>> "yes" jedoch nie terminiert.
>>
>> while read line
>> do
>> echo "-> $line"
>> done <<< $(yes)
>
> Das ist nur eine Abk�rzung f�r normale Here-Documents und benimmt sich
> daher im Wesentlichen genauso.
>
> Was funktioniert, wenn die Shell das unterst�tzt, ist
> while read line; do
> echo "-> $line"
> done < <(yes)
> Hier legt die Shell eine (named) pipe an, an deren Schreiber-Ende 'yes'
> steht, und ersetzt '<(yes)' durch den Namen der Pipe. Damit ist das
> ganze syntaktisch wieder eine normale Eingabeumleitung.
So geht's, das scheint allerdings ebenfalls eine Bash-Erweiterung zu
sein.
Gr��e
J�rg