Liebe MitListige, intensive Recherchen in der Manpage und gedruckter Literatur zur Bash sowie in Mailinglistenarchiven haben zu folgendem Vorhaben nichts nennenswertes ergeben: Ich möchte in einem Skript mehrere Hintergrundjobs nacheinander starten, d.h. die Bash soll (zunächst) nicht warten, bis einer fertig ist, sondern alle Jobs auf die Reise schicken und danach gleich wieder weitere Anweisungen synchron ausführen. Weiter unten im Skript soll dann jedoch auf die Rückkehr (die Beendigung) aller Jobs gewartet werden, wobei die Rückgabewerte aller Hintergrundjobs ermittelt werden sollen. So könnte das in etwa aussehen: # Alle Backups parallel laufen lassen for SRC_DIR in $SRC_DIR_LIST ; do rsync <options> $SRC_DIR $DEST_DIR & PID_LIST="$! " done # Weitere Anweisungen, synchron zur for-Schleife ... ... ... # Jetzt aber auf den Abschluss aller Backups warten wait $PID_LIST exit_status=$? # Der Rest des Skripts kommt hier ... ... ... aber auch das Problem: man weiß nicht, in welcher Reihenfolge die Jobs fertig werden. Bei dem wait-Kommando dürfte anschließend in exit_status nur derjenige des zuletzt terminierenden rsync-Prozesses stehen. Was aber passiert, wenn man in einer weiteren Schleife die Rückgabewerte aller rsync-Prozesse ermittelt, etwa so: for PID in $PID_LIST ; do wait $PID exit_status_list="$? " done Hier zweifle ich stark, ob das überhaupt funktioniert, denn 1. Hier wird der Sinn der oben gewollten Asynchronität der Hintergrundjobs konterkariert, weil für eine PID, deren Prozess noch nicht terminiert ist, in dieser for-Schleife gewartet wird, bis er beendet ist. 2. Es ist nicht klar, ob wait $PID bei einem vor der for-Schleife schon beendeten Job noch den exit_status zurückgibt und was demnach in der exit_status_list landet. Ein simples abschließendes wait ohne Parameter würde die Shell bis zur Terminierung des letzten Hintergrundjobs warten lassen, aber leider bekommt man dann als Rückgabewert nur 0, was nichts über den Erfolg oder Misserfolg der Hintergrundprozesse aussagt. Willkommen wäre mir ein Hinweis, wo man solche grundlegenden Bash-Programmier-Fragen und -Lösungen nachschlagen kann. Vielen Dank schon mal für die Mühe! Gruß, Tom P.S.: Folgenden Bash-Manpage-Ausschnitte waren für mich zunächst Grundlage: "If a command is terminated by the control operator &, the shell executes the command in the background in a subshell. The shell does not wait for the command to finish, and the return status is 0 [Anm: der Subshell]. Commands separated by a ; are executed sequentially; the shell waits for each command to terminate in turn. The return status [Anm.: der das Kommando startenden Shell] is the exit status of the last command executed" "wait [n ...] Wait for each specified process and return its termination status. Each n may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If n is not given, all currently active child processes are waited for, and the return status is zero. If n specifies a non-existent process or job, the return status is 127. Otherwise, the return status is the exit status of the last process or job waited for." -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Am Donnerstag, 28. Januar 2010 18:32:57 schrieb Thomas Michalka: Hallo Thomas,
Ich möchte in einem Skript mehrere Hintergrundjobs nacheinander starten, d.h. die Bash soll (zunächst) nicht warten, bis einer fertig ist, sondern alle Jobs auf die Reise schicken und danach gleich wieder weitere Anweisungen synchron ausführen. Weiter unten im Skript soll dann jedoch auf die Rückkehr (die Beendigung) aller Jobs gewartet werden, wobei die Rückgabewerte aller Hintergrundjobs ermittelt werden sollen. So könnte das in etwa aussehen:
# Alle Backups parallel laufen lassen for SRC_DIR in $SRC_DIR_LIST ; do rsync <options> $SRC_DIR $DEST_DIR & PID_LIST="$! " done
Ich wuerde einen Zaehler in die Schleife einbauen und die PID's in ein Array[Zaehlernummer] schreiben. So kannst Du die Auswertung in einer while-Schleife gezielt abrufen und dort warten, bis alle Prozesse beendet sind. "PID_LIST" finde ich hier vom Handling her unuebersichtlich. Das ist nur eine Idee, die _ich_ angehen wuerde. MfG Th. Moritz -- Solange der Nagellack nicht trocken ist, ist eine Frau wehrlos… (Burt Reynolds) -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Am Donnerstag, 28. Januar 2010 18:32:57 schrieb Thomas Michalka: Hallo Thomas, Dein Mailer ist suboptimal konfiguriert! Hier solltest Du anfangen, Probleme aus der Welt zu schaffen. ----------------------------------------------------------- Attention: Non-Delivery Report ----------------------------------------------------------- This report is generated by the email server at: pcadmin.uldrian-maschinenbau.de The message with subject: "Re: [opensuse-programming-de] Bash - Exit Status von Hintergrundjobs ermitteln" and attached to this report was not delivered to the following recipients: Address: suse-programming@uldrian-maschinenbau.de Reason: 5.1.1 User unknown (550) -------------- MfG Th. Moritz -- Wer säuft wird müde. Wer müde wird, schläft. Wer schläft, sündigt nicht. Wer nicht sündigt, kommt in den Himmel. Also: Lasst uns saufen! -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Hallo, Thomas Moritz schrieb:
Am Donnerstag, 28. Januar 2010 18:32:57 schrieb Thomas Michalka:
Hallo Thomas, Dein Mailer ist suboptimal konfiguriert! Hier solltest Du anfangen, Probleme aus der Welt zu schaffen.
Sicher nicht die Probleme anderer, außer Programmierprobleme, die hier gepostet werden, wenn ich helfen kann. Bitte überleg mal: wieso hast gerade _Du_ diesen Hinweis von diesem selbsternannten 'Postmeister' erhalten (vergleiche mal Deine Absendezeit mit der des Postmeisters und dann mit meiner!), da Du doch selber, genau wie ich, sicher nur an die Liste adressiert hast? Solche Unzustellbarkeits-Mails bekommt man nicht, wenn andere an eine nicht existierende Adresse schreiben, sondern nur, wenn man es selber tut. Allerdings kannst Du genausowenig für diesen Unzustellbarkeitshinweis wie ich, sondern es ist dieser 'Postmeister', der gleich zwei Fehler macht: Erstens erkennt er nicht, dass er die Mails von einer Mailingliste erhalten hat, da er uns ursprüngliche Absender belästigt. Zweitens versäumt er, die Adresse bei der Mailingliste auszutragen, oder sie erreichbar zu halten. Weiteres evtl. per PM. Gruß, Tom P.S.: Ich werde gleich sehen, ob der 'Postmeister' wieder darauf anspringt, aber Du nicht, solange Du hier nichts postest. Aber wer will das schon ;-) -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Am Freitag, 29. Januar 2010 09:55:00 schrieb Thomas Michalka: Hallo Thomas,
Thomas Moritz schrieb:
Am Donnerstag, 28. Januar 2010 18:32:57 schrieb Thomas Michalka:
Hallo Thomas, Dein Mailer ist suboptimal konfiguriert! Hier solltest Du anfangen, Probleme aus der Welt zu schaffen. [...]
Leider habe ich Dich in der Eile gestern Abend voellig grundlos und oeffentlich auf eine Fehlkonfiguration hingewiesen. Da man geschriebene Mails nicht zuruecknehmen kann, bleibt mir nur die oeffentliche Entschuldigung! In der Hoffnung auf Akzeptanz bitte ich das Thema zu beenden. MfG Th. Moritz -- Bigamie bedeutet, eine Frau zu viel zu haben. Monogamie ist dasselbe! (Rowan Atkinson) -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Hallo Thomas, Entschuldigung angenommen - kann einem im Eifer des Gefechts schon mal passieren. Die Sache ist für mich aus der Welt. Viele Grüße, Tom -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Moin, Am Donnerstag, 28. Januar 2010 18:32:57 schrieb Thomas Michalka:
Ich möchte in einem Skript mehrere Hintergrundjobs nacheinander starten, d.h. die Bash soll (zunächst) nicht warten, bis einer fertig ist, sondern alle Jobs auf die Reise schicken und danach gleich wieder weitere Anweisungen synchron ausführen. Weiter unten im Skript soll dann jedoch auf die Rückkehr (die Beendigung) aller Jobs gewartet werden, wobei die Rückgabewerte aller Hintergrundjobs ermittelt werden sollen. [...]
Hast Du Dir mal den Abschnitt "JOB CONTROL" in der bash-Manualpage zu Gemüte geführt? Unter anderem das Kommando "jobs" könnte helfen. Gruß Jan -- Homepage: http://www.jan-trippler.de -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Hallo Jan, Jan Trippler schrieb:
Moin,
Am Donnerstag, 28. Januar 2010 18:32:57 schrieb Thomas Michalka:
Ich möchte in einem Skript mehrere Hintergrundjobs nacheinander starten, d.h. die Bash soll (zunächst) nicht warten, bis einer fertig ist, sondern alle Jobs auf die Reise schicken und danach gleich wieder weitere Anweisungen synchron ausführen. Weiter unten im Skript soll dann jedoch auf die Rückkehr (die Beendigung) aller Jobs gewartet werden, wobei die Rückgabewerte aller Hintergrundjobs ermittelt werden sollen. [...]
Hast Du Dir mal den Abschnitt "JOB CONTROL" in der bash-Manualpage zu Gemüte geführt? Unter anderem das Kommando "jobs" könnte helfen.
Habe ich, und folgende Passage hat mir zu denken gegeben, aber ich bin mir nicht sicher, ob ich alles verstanden habe: "The shell learns immediately whenever a job changes state." Ok, die Shell wacht über den Status ihrer Kindprozesse, bzw. den Status des letzten Kindprozesses einer Pipe, richtig? "Normally, bash waits until it is about to print a prompt before reporting changes in a job's status so as to not interrupt any other output." Gilt _nur_ für den Start eines Jobs aus einer Bash in einem Terminal. Die Bash berichtet erst über den Status eines Jobs, wenn der Job fertig ist *UND* wenn man (z.B. durch die Eingabetaste) einen neuen Prompt anfordert, korrekt? "If the -b option to the set builtin command is enabled, bash reports such changes immediately." Das hilft mir aber in einem Skript, das vom crond gestartet wird, nicht wirklich, denn hier gibt die Shell mangels Terminal ja keinen Promt aus. Verstehe ich das richtig so? "Any trap on SIGCHLD is executed for each child that exits. Das könnte interessant sein. Christian Boltz hat das gefunden - ich jetzt auch ;-) Gruß, Tom -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Hallo Thomas, hallo Leute, Am Donnerstag, 28. Januar 2010 schrieb Thomas Michalka:
# Alle Backups parallel laufen lassen for SRC_DIR in $SRC_DIR_LIST ; do rsync <options> $SRC_DIR $DEST_DIR & PID_LIST="$! " done
# Jetzt aber auf den Abschluss aller Backups warten wait $PID_LIST exit_status=$?
# Der Rest des Skripts kommt hier ...
Was aber passiert, wenn man in einer weiteren Schleife die Rückgabewerte aller rsync-Prozesse ermittelt, etwa so:
for PID in $PID_LIST ; do wait $PID exit_status_list="$? " done
Hier zweifle ich stark, ob das überhaupt funktioniert, denn
1. Hier wird der Sinn der oben gewollten Asynchronität der Hintergrundjobs konterkariert, weil für eine PID, deren Prozess noch nicht terminiert ist, in dieser for-Schleife gewartet wird, bis er beendet ist.
Wäre in Deinem Fall ja nicht wirklich ein Problem, wenn ich die Kommentare in Deinem Script ("Jetzt aber auf den Abschluss aller Backups warten") richtig interpretiere. Unschön ist es trotzdem.
2. Es ist nicht klar, ob wait $PID bei einem vor der for-Schleife schon beendeten Job noch den exit_status zurückgibt und was demnach in der exit_status_list landet.
Teste das doch einfach selbst ;-) # true & [1] 16758 [1]+ Fertig true # false & [1] 16760 [1]+ Exit 1 false # wait 16758 # echo $? 0 # wait 16760 # echo $? 1 -> ja, die Bash merkt sich den Exitcode ihrer Kindprozesse. Ich hab noch was interessantes in der Bash-manpage gefunden: Any trap on SIGCHLD is executed for each child that exits. Die Hintergrundprozesse können sich also per Callback melden, wenn sie fertig sind ;-) Ich weiß nicht, ob da die PID irgendwie mitgeliefert wird, aber immerhin könntest Du damit einen Zähler a la "noch 3 Kindprozesse" bauen. (Weiter unten hab ich Dir auch noch ein besseres Callback notiert.)
Willkommen wäre mir ein Hinweis, wo man solche grundlegenden Bash-Programmier-Fragen und -Lösungen nachschlagen kann.
Nunja, sowas wie Deine Frage würde ich nicht als "grundlegende Bash- Programmier-Frage" einstufen ;-) Ich habe dazu auch noch die interessante Aufgabenstellung "Variablen aus der Subshell"[1] in Erinnerung. Vielleicht kannst Du ja mit einem zusätzlichen Ausgabekanal, auf dem die Hintergrundprozesse schreiben, was anfangen (keine Ahnung, wie sich meine Tricks mit Hintergrundprozessen vertragen - ich habe das nie getestet). So, und jetzt die pragmatische Lösung: verwende eine andere Methode zur Erkennung, welche Prozesse noch laufen ;-) Eine Variante wäre beispielsweise, pro Prozess ein Tempfile[2] mit dem Exitcode anzulegen: for SRC_DIR in $SRC_DIR_LIST ; do { rsync <options> $SRC_DIR $DEST_DIR ; echo $? > tmp_$SRC_DIR ; # [2] }& PID_LIST="$! " Damit schlägst Du ein paar Fliegen mit einer Klappe: - Du siehst, wann ein Prozess fertig ist: test -f tmp_irgendwas && echo "fertig" - Im Tempfile steht der Exitcode, den Du problemlos einem Prozess (wichtiger: einem Backup-Verzeichnis) zuordnen kannst - Du kannst problemlos über alle Prozesse/Tempfiles einen Loop machen, ohne irgendwie geblockt zu werden ("test -f" oder "test -s") - Wenn alle angefragten Tempfiles existieren und jeweils eine "0" enthalten, ist das Backup komplett und erfolgreich ;-) Noch eine Variante ohne Tempfiles: Bau Dir selbst ein Callback ;-) Das ist besser als SIGCHLD, weil Du damit den Exitstatus und z. B. das gesicherte Verzeichnis durchreichen kannst. Bei der Gelegenheit kannst Du auch gleich ein Logfile schreiben usw. - die Lösung ist flexibel ;-) function child_finished() { echo "Status: $1" echo "Dir: $2" return $1 # exit-Status durchreichen, damit er z. B. für wait # sichtbar wird } for SRC_DIR in $SRC_DIR_LIST ; do { rsync <options> $SRC_DIR $DEST_DIR ; child_finished $? $SRC_DIR } & So, das sollten genug Anregungen für heute Nacht sein. Wie Du siehst, hat Programmierung auch immer ein Stück weit mit Kreativität zu tun ;-) Gruß Christian Boltz [1] www.cboltz.de/de/linux/bash/ [2] dass das Ganze innerhalb eines "mktemp -d"-Verzeichnisses ablaufen sollte, versteht sich von selbst, oder? --
Kann mir bitte jemand das Script für die Abmeldung von dieser Liste schicken. ist schon wieder der erste April?? [> Josef Schwendt und Andreas Kyek in suse-linux] -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
Hallo Christian, Christian Boltz schrieb:
Hallo Thomas, hallo Leute,
Am Donnerstag, 28. Januar 2010 schrieb Thomas Michalka:
# Alle Backups parallel laufen lassen for SRC_DIR in $SRC_DIR_LIST ; do rsync <options> $SRC_DIR $DEST_DIR & PID_LIST="$! " done
# Jetzt aber auf den Abschluss aller Backups warten wait $PID_LIST exit_status=$?
# Der Rest des Skripts kommt hier ...
Was aber passiert, wenn man in einer weiteren Schleife die Rückgabewerte aller rsync-Prozesse ermittelt, etwa so:
for PID in $PID_LIST ; do wait $PID exit_status_list="$? "
Sollte heißen: exit_status_list="exit_status_list$? "
done
Hier zweifle ich stark, ob das überhaupt funktioniert, denn
1. Hier wird der Sinn der oben gewollten Asynchronität der Hintergrundjobs konterkariert, weil für eine PID, deren Prozess noch nicht terminiert ist, in dieser for-Schleife gewartet wird, bis er beendet ist.
Wäre in Deinem Fall ja nicht wirklich ein Problem, wenn ich die Kommentare in Deinem Script ("Jetzt aber auf den Abschluss aller Backups warten") richtig interpretiere.
Stimmt, das sehe ich jetzt auch, denn ich lasse diese zweite for-Schleife ja erst laufen, wenn ich im Skript an eine Stelle komme, wo ich alle Rückgabewerte prüfen muss. Ist ein Prozess bis dahin noch nicht fertig, dann wartet die Schleife halt, bis er fertig ist und ermittelt die Rückgabewerte der restlichen Hintergrundprozesse danach. Voraussetzung dafür ist allerdings, dass sich die aufrufende Bash _alle_ Exitcodes ihrer Kindprozesse merkt (was der Fall ist, wie Du mir gezeigt hast :-D ).
Unschön ist es trotzdem.
Ich finde es nicht unelegant, zumindest für meinen Bedarf, denn ich muss gar kein umständliches Polling selber programmieren (das tut die Bash mit dem wait-Kommando für mich, auch wenn sie wohl nicht wirklich pollt, sondern vermutlich auf ein Signal der Subshell wartet), auch keine Ausgaben in temporäre Dateien, u.ä Hilfskonstrukte. Wenn das mit dem wait bash-intern aber so geht, warum soll man ein solches Feature nicht nutzen?
2. Es ist nicht klar, ob wait $PID bei einem vor der for-Schleife schon beendeten Job noch den exit_status zurückgibt und was demnach in der exit_status_list landet.
Doch, das ist es jetzt dank Deines Hinweises - das war für mich der Schlüssel :-)
Teste das doch einfach selbst ;-)
# true & [1] 16758 [1]+ Fertig true # false & [1] 16760 [1]+ Exit 1 false # wait 16758 # echo $? 0 # wait 16760 # echo $? 1
-> ja, die Bash merkt sich den Exitcode ihrer Kindprozesse.
So ähnlich habe ich es auch probiert, aber weil ich dazwischen ein einfaches wait (ohne Parameter) abgesetzt habe, ging das nicht. Ich habe auch noch getestet, ob man zwischen dem Start des Hintergrundprozesses und dem wait $PID beliebige andere Befehle abarbeiten kann. Dies scheint, bis auf das einfache wait eben, der Fall zu sein. Das wait-Kommando scheint die Liste der Kindprozesse der aufrufenden Bash zu löschen, weswegen ein späteres wait $PID folgende Meldung ergibt: bash: wait: pid 30738 is not a child of this shell
Ich hab noch was interessantes in der Bash-manpage gefunden:
Any trap on SIGCHLD is executed for each child that exits.
Die Hintergrundprozesse können sich also per Callback melden, wenn sie fertig sind ;-)
Das wär's natürlich ... Durch Lektüre des Manpage-Abschnitts konnte ich allerdings nicht herausfinden, ob ein trap <command> <signal> auch einen Rückgabewert zurückerhält und an <command> weitergibt.
Ich weiß nicht, ob da die PID irgendwie mitgeliefert wird, aber immerhin
Hätte das sonst einen Sinn?
könntest Du damit einen Zähler a la "noch 3 Kindprozesse" bauen.
Das wäre dann zu wenig, weil ich danach ggf. nicht sagen könnte, welcher Kindprozess gescheitert ist.
(Weiter unten hab ich Dir auch noch ein besseres Callback notiert.)
Willkommen wäre mir ein Hinweis, wo man solche grundlegenden Bash-Programmier-Fragen und -Lösungen nachschlagen kann.
Nunja, sowas wie Deine Frage würde ich nicht als "grundlegende Bash- Programmier-Frage" einstufen ;-)
Das Überprüfen von Exitcodes von Hintergrundprozessen halte ich schon für elementar, weil man sonst bei asynchronen Aufrufen keine vernünftige Fehlerbehandlung durchführen könnte.
Ich habe dazu auch noch die interessante Aufgabenstellung "Variablen aus der Subshell"[1] in Erinnerung. Vielleicht kannst Du ja mit einem zusätzlichen Ausgabekanal, auf dem die Hintergrundprozesse schreiben, was anfangen (keine Ahnung, wie sich meine Tricks mit Hintergrundprozessen vertragen - ich habe das nie getestet).
So, und jetzt die pragmatische Lösung: verwende eine andere Methode zur Erkennung, welche Prozesse noch laufen ;-) Eine Variante wäre beispielsweise, pro Prozess ein Tempfile[2] mit dem Exitcode anzulegen:
for SRC_DIR in $SRC_DIR_LIST ; do { rsync <options> $SRC_DIR $DEST_DIR ; echo $? > tmp_$SRC_DIR ; # [2] }& PID_LIST="$! "
Wenn ich das richtig sehe, willst Du hier eine Subshell starten. Mit den beiden Kommandos rsync und echo darin. Eigentlich müsste dann die PID der Subshell in der PID_LIST landen, nicht die von echo und erst recht nicht die von rsync, denn das ist nicht das letzte Kommando in der Subshell.
Damit schlägst Du ein paar Fliegen mit einer Klappe: - Du siehst, wann ein Prozess fertig ist: test -f tmp_irgendwas && echo "fertig"
Das ginge eleganter ohne temporäre Dateien: man kann die PIDs in einer Liste speichern und später wieder in einer (Endlos-)Schleife reihum lesen und mit if ! ps r | grep -q "$PID" ; then ... ; fi Wird grep fündig, dann existiert der Prozess noch und läuft auch (r = running), wenn nicht, dann ist der Prozess wohl fertig (er könnte aber auch unterbrochen sein oder einen anderen Zustand einnehmen).
- Im Tempfile steht der Exitcode, den Du problemlos einem Prozess (wichtiger: einem Backup-Verzeichnis) zuordnen kannst
Das geht aber doch auch innerhalb meines Skripts, ganz ohne temporäre Dateien, denn durch die erste for-Schleife gibt es eine eindeutige Zuordnung zwischen PID_LIST und der Liste der zu sichernden Verzeichnisse B_SRCDIR_LIST.
- Du kannst problemlos über alle Prozesse/Tempfiles einen Loop machen, ohne irgendwie geblockt zu werden ("test -f" oder "test -s")
Kann ich auch mit PID_LIST und B_SRCDIR_LIST, wie meine zweite for-Schleife zeigt (zugegebenermaßen nur unvollständig und mit einem Fehler, aber prinzipiell).
- Wenn alle angefragten Tempfiles existieren und jeweils eine "0" enthalten, ist das Backup komplett und erfolgreich ;-)
Diese Lösung wäre in Betracht gekommen, wenn sich die Bash die Exitcodes ihrer Kindprozesse nicht merken würde. Aber dass sie es tut, ist doch elegant!
Noch eine Variante ohne Tempfiles: Bau Dir selbst ein Callback ;-) Das ist besser als SIGCHLD, weil Du damit den Exitstatus und z. B. das gesicherte Verzeichnis durchreichen kannst. Bei der Gelegenheit kannst Du auch gleich ein Logfile schreiben usw. - die Lösung ist flexibel ;-)
function child_finished() { echo "Status: $1" echo "Dir: $2" return $1 # exit-Status durchreichen, damit er z. B. für wait # sichtbar wird }
for SRC_DIR in $SRC_DIR_LIST ; do { rsync <options> $SRC_DIR $DEST_DIR ; child_finished $? $SRC_DIR } & exitstatus=$? # Sollte nicht so oder ähnlich der Exit-Status # in der aufrufenden Shell gespeichert werden? # Funktioniert aber wohl nicht, da der Exit-Status # des letzten ausgeführten Kommandos, von 'do' # also, zugewiesen würde done # (durfte ich doch ergänzen?)
Das Problem hier ist aber doch genau dasselbe, nämlich dass Du nicht weißt, wann child_finished in der Subshell aufgerufen wird. Daher weißt Du auch nicht, wann und wie Du den Return-Wert von welchem Hintergrundprozess in die aufrufende Shell in $? zurückgeliefert bekommst. Vielleicht ginge es, in der Callback-Funktion den Rückgabewert in eine globale Variable zu schreiben, aber mir ist momentan nicht ganz klar, ob das mit dem neuen Environment der Subshell hinhaut. Außerdem sehe ich den Sinn des Durchreichens des Returnwertes nicht ein, da eine Subshell als Exitcode doch ohnehin den Exit-Status des in ihr zuletzt ausgeführten Kommandos zurückliefert. Kurz gesagt: Ich verstehe nicht, wie Du hier das Problem löst, dass die aufrufende Shell die Exit-Stati erhält und nach der Beendigung des letzten aktiven Hintergrundprozesses alle irgendwo gespeichert hat. Und wie signalisiert child_finished () der aufrufenden Shell die Beendigung der Subshell und damit von rsync? Wenn Du wait (natürlich in der Form wait $PID) verwendest, wie Du kommentierst, dann kannst Du Dir child_finished auch sparen, denn for SRC_DIR in $SRC_DIR_LIST ; do rsync <options> $SRC_DIR $DEST_DIR & PID_LIST="$PID_LIST$! " done liefert Dir alle PIDs, die Du dann in einer später aufgerufenen zweiten for-Schleife eindeutig den Return-Werten mittels wait $PID zuordnen kannst (von mir aus auch in einem Array, damit man bei der Kodierung der Zuordnung Fehler vermeidet). Gruß, Tom -- To unsubscribe, e-mail: opensuse-programming-de+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-programming-de+help@opensuse.org
participants (4)
-
Christian Boltz
-
Jan Trippler
-
Thomas Michalka
-
Thomas Moritz