Variable aus Child-Prozess "Re-exportieren"

E

-eraz-

Tripel-As
Gibts ne Möglichkeit, wie ich eine in einem Child Prozess erstelle Variable zurückbringe in den Mutterprozess?
Ich möchte aus einer Schleife wieder entkommen wenn ein Child Prozess seine Arbeit verrichtet hat, ich spiele da grad ein bisschen rum, aber ne andere Lösung als z.b. die hier ist mir nicht eingefallen:

Code:
function test {
   sleep 10
   echo "5" > /tmp/x
}

i=4
for (( x=0; $x<=$i; x=$x+1 )); do

   pid=$(echo $$)
   if [ `ps -ef |grep $pid |wc -l` -le 2 ]; then
        test &
   fi

   if [ -e /tmp/x ]; then
        rm -f /tmp/x
        x=5
   else
        p1="."
        p2=".."
        p3="..."
        clear
        echo
        eval echo "Sammle Daten, bitte warten \$p$x"
        sleep 0.3
   fi

   if [ $x = 4 ]; then
        x=0
   fi

done

Funktioniert aber nicht 100%ig /tmp/x wird manchmal nicht gelöscht und nach Beendigung der Schleife bleiben der Prozess "test" und "sleep" noch eine Weile bestehen.

PS: Bezieht sich auf Bash
 
Zuletzt bearbeitet:
so...?
Code:
HBtux:/tmp/test # cat test1.sh
#!/bin/bash

testfunktion () {
        echo "testfunktion aufgerufen"
        sleep 3
        XX="5"
}

XX="1"
echo $XX
testfunktion
echo $XX

ergibt folgende Ausgabe....
Code:
HBtux:/tmp/test # ./test1.sh
1
testfunktion aufgerufen
5
 
Nein das befreit mich leider nicht aus der Schleife, weil die Variable $XX (lt. deinem Beispiel) oder $x (lt. meinem Beispiel) die im Child-Prozess verändert wird, vom "Mutterprozess" nicht erkannt wird (auch nicht per export).
 
folgende kleine Tipps am Rande.....

"test" solltest Du nicht als Namen für eine Funktion nehmen, da es einen Betriebssystembefehl namens test gibt....


pid=$(echo $$)
geht so auch einfacher ...
pid=$$


Sonst fällt mir leider auch nur zurückschreiben über Pipe ein.... :think:
 
Hi,

wenn ich das richtig verstehe, willst du einen Prozess starten, der sein Ergebnis z.B. nach /tmp/x schreibt, dann im Parent-Prozess darauf warten, dass der fertig wird und sein Resultat abholen?

Dann scheint mir der Check innerhalb der Schleife, ob nicht schon mehr als 2 Prozesse laufen, unnötig kompliziert: du kannst ja den Child-Prozess vor der Schleife anwerfen, und dann solange warten, bis der fertig ist, entweder gleich mit "wait $!", oder mit einer kleinen kill-Schleife.

Wenn der Kind-Prozess dann sein Ergebnis in eine Datei geschrieben hat, kannst du die ja ganz einfach einlesen.

Das Folgende könnte etwa als Ansatz dienen:

Code:
#!/bin/sh


run() {
        sh -c "echo START \$\$; sleep 3; echo \"X=$RANDOM\" >/tmp/\$\$.out" &
}


run
CHILD=$!
sleep 1


cleanup() {
        kill -HUP $CHILD 2>/dev/null
        sleep 1
        rm -f /tmp/$CHILD.out
}
trap cleanup 0

X="?"
echo -n "$$: Warte auf $CHILD ."
while kill -0 $CHILD 2>/dev/null; do
        echo -n .
        sleep 1
done
echo

eval $(</tmp/$CHILD.out)
echo "$CHILD liefert $X"

exit 0

Das Ganze zu erweitern auf z.B. mehrere parallell laufende run-Prozesse (über einen Array von Child-Prozess-Pids), einen Timeout einzubauen etc. dürfte trivial sein.

Hoffe, das hilft dir mal weiter ...


Gruss, A.
 
wenn ich das richtig verstehe, willst du einen Prozess starten, der sein Ergebnis z.B. nach /tmp/x schreibt, dann im Parent-Prozess darauf warten, dass der fertig wird und sein Resultat abholen
Nicht ganz, das schreiben von x=5 nach /tmp/x dient eigentlich nur dazu den Parent Prozess aus seiner Schleife zu befreien, sobald der Child-Prozess fertig ist. Aber die Methode die ich da gewählt habe scheint eh nicht sauber zu funktionieren, warum auch immer ...

Dann scheint mir der Check innerhalb der Schleife, ob nicht schon mehr als 2 Prozesse laufen, unnötig kompliziert: du kannst ja den Child-Prozess vor der Schleife anwerfen
Stimmt, hast Recht :)

Ich schau mir deine Lösung an, ich hoffe ich steig da durch, sind schon wieder soviele neue Sachen dabei. :D

/edit

@floyd62
Mit Arrays hab ich bisher noch nie was gemacht, hast du da vielleicht ein kleines Beispiel?
Und andere Frage: Was bewirkt die "cleanup" funktion bzw. der trap Befehl mit dem sie aufgerufen wird?
.
.
.
EDIT (autom. Beitragszusammenführung) :
.

Ich glaub das was ich brauche dürfte das hier sein :) :

Code:
#!/bin/bash

function funktion {
   sleep 3
}

function funktion2 {
   sleep 3
}

function execute_functions {
   funktionen=("funktion" "funktion2")
   for (( i=0; i<${#funktionen}; i++ )); do
       ${funktionen[$i]}
   done
}

execute_functions &
CHILD=$!

i=4
p1="."
p2=".."
p3="..."
for (( x=0; $x<=$i; x=$x+1 )); do
   kill -0 $CHILD 2>/dev/null
   if [ $? = 1 ]; then
        x=5
   else
        clear
        echo
        eval echo "Sammle Daten, bitte warten \$p$x"
        sleep 0.3
   fi

   if [ $x = 4 ]; then
        x=0
   fi
done

Tut bisher genau das was ich will, muss ich aber noch ausgiebig testen, danke floyd62 für die Hilfe :)

PS: Shell scripten is GEIL!! :D
 
Zuletzt bearbeitet:
Na wenns denn läuft ;) ...

Nur noch kurz zur Ergänzung: mit Hilfe von "trap" kannst du in der Shell eine Funktion definieren, die beim Eintreffen von Signalen (1 "HUP", 2 "INTR", 3 "QUIT") bzw. beim Beenden des Skripts (0) noch aufgerufen wird. Was ich damit erreichen wollte (und mit
Code:
trap cleanup 0 1 2 3
wahrscheinlich auch erreicht hätte) ist, dass ich das Skript z.B. mit Ctrl-C von der Konsole aus abbrechen hätte können, und dass beim Beenden auf jeden Fall auch ein noch laufender Child-Prozess mit Hangup-Signal abgeschossen und das Ergebnis-File gelöscht worden wäre ... man will ja den Schrott in /tmp nicht bis zum nächsten Reboot rumhängen lassen ...

In der neuen Version deines Skripts werden die Funktionen übrigens nicht parallell in den Hintergrund geschickt, sondern schön sequentiell abgearbeitet, was du z.B. mit Ergänzungen wie
Code:
function funktion {
   echo START funktion
   sleep 3
   echo ENDE funktion
}
leicht sehen kannst. Weiss nicht, ob das so gedacht war ...

Ganz am Rande: wenn du den Wert von $x nur auf 5 setzt, damit du aus der Schleife fliegst, das sollte sich auch einfacher mit dem "break" Kommando lösen lassen, etwa
Code:
kill -0 $CHILD 2>/dev/null
if [ $? = 1 ]; then break; fi

Die Geschichte mit den Arrays hast du ja sowieso schon gepeilt ...

Und, ja, schon spassig, die Shell - man sieht doch immer wieder mal was Neues ...

Gruss, A.
 
Danke für die Erklärung... im Laufe meiner "Einbauarbeit" ins "echte" Skript hat sich dann eh noch herausgestellt, das ich die Cleanup Funktion sehr gut brauchen kann. :)
Das mit dem sequentiellen abarbeiten ist übrigens beabsichtigt, die Funktionen die in der Endversion des Skripts aufgerufen werden sind zum Teil etwas Performancelastig und ich will nicht das mir da ein Server in die Knie geht sobald das Skript aufgerufen wird.

Achja, eins hab ich übrigens noch immer nicht kapiert, und zwar was hier passiert:
Code:
eval $(</tmp/$CHILD.out)
Wenn ich das richtig sehe, wird die Ausgabe des CHILD Prozesses eingelesen, aber wohin?
Vermutlich in X oder? Aber ich check nicht ganz wie es in X reinkommt durch den Befehl...?:think:
 
Zuletzt bearbeitet:
Achja, eins hab ich übrigens noch immer nicht kapiert, und zwar was hier passiert:
Code:
eval $(</tmp/$CHILD.out)
Wenn ich das richtig sehe, wird die Ausgabe des CHILD Prozesses eingelesen, aber wohin?
Vermutlich in X oder? Aber ich check nicht ganz wie es in X reinkommt durch den Befehl...?:think:

Schaue mal weiter oben im Script, was in die Datei /tmp/$CHILD.out geschrieben wird.....
Setze nun genau diese Zeichen innerhalb der Klammer ein und Du hast das Ergebnis.....
Code:
.... echo \"X=$RANDOM\" >/tmp/\$\$.out
....
eval $(</tmp/$CHILD.out)

das entspricht aufgelöst.....

X=$RANDOM
Es wird also einfach die Variable X gesetzt.
 
Ja schon, aber weiter oben setzt er ja X auf "?". Und bei eval lest er die datei in PID.out wieder in X ein. ABER, bei dem eval Befehl ist ja nirgens angegeben, dass der Inhalt von PID.out in X gelesen werden soll, also woher weiß die Shell das

"eval $(</tmp/$CHILD.out)"

ausgerechnet in die Variable X gelesen werden soll?
 
Hi,

wie HBTux richtig erklärt: der Sohnprozess schreibt innerhalb der run()-FUnktion nicht nur den neuen Wert für X in die Ausgabedatei, sondern eine Anweisung, mit der der neue Wert für X gesetzt wird ("X=$RANDOM"). Mit $(<FILE) bekommst du den Inhalt einer Datei FILE als String, und den kannst du dann - wenn es denn ein gültiges Shell-Kommando ist - mit eval auswerten. Auf diese Weise könntest du dann auch mehrere Variablen an den Parent-Prozess zurückliefern ...

Gruesse, A.
 
Komentiere doch spasseshalber mal die Zeile "rm -f /tmp/$CHILD.out" aus und schaue nach dem Ausführen des Script mal in diese Temp-Datei rein, was dort drinnen steht.....
Ich denke dann dürfte es klar sein, dass eval mit dem Inhalt macht.....

Der Inhalt so so oder ähnlich aussehen.....
Code:
[B]cat /tmp/$CHILD.out[/B]   (bzw. [B]cat /tmp/2754.out[/B] - entsprechend der verwendeten PID)
[B]X=2754[/B]
 

Ähnliche Themen

Verschlüsseltes Backup-Script mit rsync

HandbrakeCLI Shell Skript

verzeichniss suche funktioniert nicht

Filtern und zuordnen

Queue für copy Script

Zurück
Oben