Discussion:
Script mit mehreren rsync Aufrufen beenden
(zu alt für eine Antwort)
Jan Novak
2020-11-24 09:43:07 UTC
Permalink
Hallo,

auf einem Server werden zu verschiedenen Zeiten mit verschiedenen (bash)
scripten mehrere rsyncs (nacheinander) gestartet.

Mit entsprechnenden PID Mechanismen, kann ich das aufgerufene Script
zwar extern beenden, jedoch wird dann immer noch der nächste rsync im
script gestartet, was nicht gewünscht ist.

Ein "killall rsync" geht auch nicht, weil andere rsyncs, aus anderen
scripten, weiter laufen sollen.

Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?


Jan
Stefan Wiens
2020-11-24 10:21:24 UTC
Permalink
Post by Jan Novak
auf einem Server werden zu verschiedenen Zeiten mit verschiedenen
(bash) scripten mehrere rsyncs (nacheinander) gestartet.
Mit entsprechnenden PID Mechanismen, kann ich das aufgerufene Script
zwar extern beenden, jedoch wird dann immer noch der nächste rsync im
script gestartet, was nicht gewünscht ist.
Ein "beendetes" Script kann keine weiteren Prozesse starten.
Post by Jan Novak
Ein "killall rsync" geht auch nicht, weil andere rsyncs, aus anderen
scripten, weiter laufen sollen.
"killall" ? Kein Kommentar.
Post by Jan Novak
Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?
Zunächst nachdenken. Wann kann bzw. soll das Script sinnvoll
weitermachen? Den Exit-Value der gestarteten Commands auswerten.

Welches Problem soll denn konkret behoben werden?
--
Stefan
Jan Novak
2020-11-24 10:31:53 UTC
Permalink
Post by Stefan Wiens
Post by Jan Novak
auf einem Server werden zu verschiedenen Zeiten mit verschiedenen
(bash) scripten mehrere rsyncs (nacheinander) gestartet.
Mit entsprechnenden PID Mechanismen, kann ich das aufgerufene Script
zwar extern beenden, jedoch wird dann immer noch der nächste rsync im
script gestartet, was nicht gewünscht ist.
Ein "beendetes" Script kann keine weiteren Prozesse starten.
Post by Jan Novak
Ein "killall rsync" geht auch nicht, weil andere rsyncs, aus anderen
scripten, weiter laufen sollen.
"killall" ? Kein Kommentar.
Post by Jan Novak
Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?
Zunächst nachdenken. Wann kann bzw. soll das Script sinnvoll
weitermachen? Den Exit-Value der gestarteten Commands auswerten.
Welches Problem soll denn konkret behoben werden?
Beispiel:

#!/bin/bash

##################### check and kill #####################
pidFile="/var/run/$(basename $0 .sh).pid"
[ -e $pidFile ] && pid=$(cat $pidFile)
if [ "$1" ] && [ "$1" = "kill" ]; then
if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps)" ] ; then
echo "Killing pid $pid ..."
kill $pid
else
echo "Nothing to kill."
fi
rm -f $pidFile
exit
fi
if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps|grep -v grep)" ]; then
echo "ERROR: Script $0 always running on $(hostname -f) (
$(hostname -i) ). Exit!" | tee /dev/stderr | mail root
exit
fi
echo $$>$pidFile
##################### check and kill #####################


rsync source dest...
rsync source dest...
rsync source dest...
rsync source dest...
rsync source dest...


Wenn jetzt ein rsync (sub-) Prozess läuft und ich das Script mit dem
Parameter "kill" aufrufe, wird der rsync przess nicht gestoppt.

Jan
Stefan Wiens
2020-11-24 12:20:03 UTC
Permalink
Post by Jan Novak
Post by Stefan Wiens
Post by Jan Novak
auf einem Server werden zu verschiedenen Zeiten mit verschiedenen
(bash) scripten mehrere rsyncs (nacheinander) gestartet.
Mit entsprechnenden PID Mechanismen, kann ich das aufgerufene Script
zwar extern beenden, jedoch wird dann immer noch der nächste rsync im
script gestartet, was nicht gewünscht ist.
Ein "beendetes" Script kann keine weiteren Prozesse starten.
Post by Jan Novak
Ein "killall rsync" geht auch nicht, weil andere rsyncs, aus anderen
scripten, weiter laufen sollen.
"killall" ? Kein Kommentar.
Post by Jan Novak
Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?
Zunächst nachdenken. Wann kann bzw. soll das Script sinnvoll
weitermachen? Den Exit-Value der gestarteten Commands auswerten.
Welches Problem soll denn konkret behoben werden?
#!/bin/bash
##################### check and kill #####################
pidFile="/var/run/$(basename $0 .sh).pid"
[ -e $pidFile ] && pid=$(cat $pidFile)
if [ "$1" ] && [ "$1" = "kill" ]; then
if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps)" ] ; then
echo "Killing pid $pid ..."
kill $pid
else
echo "Nothing to kill."
fi
rm -f $pidFile
exit
fi
if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps|grep -v grep)" ]; then
echo "ERROR: Script $0 always running on $(hostname -f) (
$(hostname -i) ). Exit!" | tee /dev/stderr | mail root
exit
fi
echo $$>$pidFile
##################### check and kill #####################
rsync source dest...
rsync source dest...
rsync source dest...
rsync source dest...
rsync source dest...
Wenn jetzt ein rsync (sub-) Prozess läuft und ich das Script mit dem
Parameter "kill" aufrufe, wird der rsync przess nicht gestoppt.
Also erstens kommt in deinem Script kein Aufruf von rsync(1) vor. Da
kann niemand sagen, wie du unerwünschte rsync-Prozesse unterdrücken
könntest.

Zweitens hat dein Script offenbar Write-Permissions nach /var/run. Da
sollte man mit dem blauäugigen herum-grep(1)-en in der Ausgabe von ps(1)
vorsichtig sein.
--
Stefan
Jan Novak
2020-11-25 10:08:57 UTC
Permalink
Post by Stefan Wiens
Post by Jan Novak
rsync source dest...
Also erstens kommt in deinem Script kein Aufruf von rsync(1) vor. Da
kann niemand sagen, wie du unerwünschte rsync-Prozesse unterdrücken
könntest.
Da oben stehts doch... was soll ich den exakten Aufruf hier posten. Ist
ein rsync -avp mit ssh source dest ... nichst aufregendes.
Post by Stefan Wiens
Zweitens hat dein Script offenbar Write-Permissions nach /var/run.
Korrekt. Es läuft als root.
Post by Stefan Wiens
Da sollte man mit dem blauäugigen herum-grep(1)-en in der Ausgabe von ps(1)
vorsichtig sein.
"Blauäugigem herum-grep'en" ;-)
Scherzkeks. Niemand greppt blauäugig in /var/run...
Du hast scheinbar die Frage nicht verstanden oder nicht richtige
gelesen. Seis drum. Danke dennoch für deinen Kommentar (ausdrücklich
nicht ironisch gemeit)

Jan
Stefan Wiens
2020-11-25 11:40:09 UTC
Permalink
Post by Jan Novak
Post by Stefan Wiens
Post by Jan Novak
rsync source dest...
Also erstens kommt in deinem Script kein Aufruf von rsync(1) vor. Da
kann niemand sagen, wie du unerwünschte rsync-Prozesse unterdrücken
könntest.
Da oben stehts doch... was soll ich den exakten Aufruf hier posten.
Ist ein rsync -avp mit ssh source dest ... nichst aufregendes.
Sind die rsync-Prozesse irgendwie in den Hintergund gestellt?
Post by Jan Novak
Post by Stefan Wiens
Zweitens hat dein Script offenbar Write-Permissions nach /var/run.
Korrekt. Es läuft als root.
Post by Stefan Wiens
Da sollte man mit dem blauäugigen herum-grep(1)-en in der Ausgabe von ps(1)
vorsichtig sein.
"Blauäugigem herum-grep'en" ;-)
Scherzkeks. Niemand greppt blauäugig in /var/run...
[...]
,----[ <rpinep$4t1$***@gwaiyur.mb-net.net> ]
| if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps)" ] ; then
`----

Der Suchstring "$pid" darf also sowohl als Teil einer anderen Process-ID
wie auch in den Argumentlisten aller Prozesse vorkommen.
--
Stefan
Jan Novak
2020-11-25 14:55:18 UTC
Permalink
Post by Stefan Wiens
Post by Jan Novak
"Blauäugigem herum-grep'en" ;-)
Scherzkeks. Niemand greppt blauäugig in /var/run...
[...]
| if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps)" ] ; then
`----
Der Suchstring "$pid" darf also sowohl als Teil einer anderen Process-ID
wie auch in den Argumentlisten aller Prozesse vorkommen.
Ja... deswegen greppt dennoch keiner in /var/run - nur in der Prozess
Liste - und dagegen ist sicher nichts einzuwenden.

Jan
Thomas Noll
2020-11-25 16:36:29 UTC
Permalink
Post by Jan Novak
Post by Stefan Wiens
Post by Jan Novak
"Blauäugigem herum-grep'en" ;-)
Scherzkeks. Niemand greppt blauäugig in /var/run...
[...]
| if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps)" ] ; then
`----
Der Suchstring "$pid" darf also sowohl als Teil einer anderen Process-ID
wie auch in den Argumentlisten aller Prozesse vorkommen.
Ja... deswegen greppt dennoch keiner in /var/run - nur in der Prozess
Liste - und dagegen ist sicher nichts einzuwenden.
Doch. So wie du es machst funktioniert es nicht.
Man kann auf eine aktive PID ohne grep testen, einfach mit ps.
man ps(1)
Und außer dir hat niemand was von grep in /var/run geschrieben.
Helmut Waitzmann
2020-11-25 21:53:34 UTC
Permalink
Post by Thomas Noll
Man kann auf eine aktive PID ohne grep testen, einfach mit ps.
Noch einfacher mit «kill»:

kill -s 0 -- "$pid"
--
Hat man erst verstanden, wie Unix funktioniert, ist auch
das Shell-Handbuch kein Buch mit sieben Siegeln mehr.
Jan Novak
2020-11-26 07:03:03 UTC
Permalink
Post by Helmut Waitzmann
Post by Thomas Noll
Man kann auf eine aktive PID ohne grep testen, einfach mit ps.
kill -s 0 -- "$pid"
Dazu musst du die PID aber kennen.
Und diese habe ich aus einer pid Datei aus /var/run/datei mit cat gelsen.
Dann mit grep in der Prozess Liste danach gesucht.
Der Vorwurf von Stefan war, ich würde wild in /var/run greppen.
Das ist nicht korrekt.

Jan
Stefan Wiens
2020-11-26 13:10:30 UTC
Permalink
Post by Jan Novak
Post by Helmut Waitzmann
Post by Thomas Noll
Man kann auf eine aktive PID ohne grep testen, einfach mit ps.
kill -s 0 -- "$pid"
Dazu musst du die PID aber kennen.
Und diese habe ich aus einer pid Datei aus /var/run/datei mit cat gelsen.
Dann mit grep in der Prozess Liste danach gesucht.
Der Vorwurf von Stefan war, ich würde wild in /var/run greppen.
Das ist nicht korrekt.
Nirgendwo habe ich dir vorgeworfen, in /var/run zu greppen:

,----[ <***@eswe.dd-dns.de> ]
| Zweitens hat dein Script offenbar Write-Permissions nach /var/run. Da
| sollte man mit dem blauäugigen herum-grep(1)-en in der Ausgabe von ps(1)
| vorsichtig sein.
`----
--
Stefan
Jan Novak
2020-11-27 07:29:53 UTC
Permalink
Post by Stefan Wiens
| Zweitens hat dein Script offenbar Write-Permissions nach /var/run. Da
| sollte man mit dem blauäugigen herum-grep(1)-en in der Ausgabe von ps(1)
| vorsichtig sein.
`----
Dann haben wir unterschiedliche Auffassungen von Meinung und
geschriebenen Wort.
Der Einfachheit halber sollten wir "dieses" Thema hier aber auf sich
beruhen lassen.

Jan
Jan Novak
2020-11-26 06:58:20 UTC
Permalink
Post by Thomas Noll
Post by Jan Novak
Post by Stefan Wiens
Post by Jan Novak
"Blauäugigem herum-grep'en" ;-)
Scherzkeks. Niemand greppt blauäugig in /var/run...
[...]
| if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps)" ] ; then
`----
Der Suchstring "$pid" darf also sowohl als Teil einer anderen Process-ID
wie auch in den Argumentlisten aller Prozesse vorkommen.
Ja... deswegen greppt dennoch keiner in /var/run - nur in der Prozess
Liste - und dagegen ist sicher nichts einzuwenden.
Doch. So wie du es machst funktioniert es nicht.
Man kann auf eine aktive PID ohne grep testen, einfach mit ps.
man ps(1)
Und außer dir hat niemand was von grep in /var/run geschrieben.
auch wenn dein Kommentar nichts mit meine eigentlichen Problem zu tuin hat:

Was ist daran falsch

[ "$(ps ax|grep $pid|grep -v ps)" ]

die pid aus einer Datei zu lesen (mit cat Datei, nicht grep)und diese
dann in der Prozess Liste zu suchen?

Jan
Thomas Noll
2020-11-26 07:55:52 UTC
Permalink
Post by Jan Novak
Post by Thomas Noll
Post by Jan Novak
Post by Stefan Wiens
Post by Jan Novak
"Blauäugigem herum-grep'en" ;-)
Scherzkeks. Niemand greppt blauäugig in /var/run...
[...]
| if [ "$pid" ] && [ "$(ps ax|grep $pid|grep -v ps)" ] ; then
`----
Der Suchstring "$pid" darf also sowohl als Teil einer anderen Process-ID
wie auch in den Argumentlisten aller Prozesse vorkommen.
Ja... deswegen greppt dennoch keiner in /var/run - nur in der Prozess
Liste - und dagegen ist sicher nichts einzuwenden.
Doch. So wie du es machst funktioniert es nicht.
Man kann auf eine aktive PID ohne grep testen, einfach mit ps.
man ps(1)
Und außer dir hat niemand was von grep in /var/run geschrieben.
Zynisch gesagt: doch.
Post by Jan Novak
Was ist daran falsch
[ "$(ps ax|grep $pid|grep -v ps)" ]
die pid aus einer Datei zu lesen (mit cat Datei, nicht grep)und diese
dann in der Prozess Liste zu suchen?
Etwas hat Stefan dir doch schon geschrieben.
additional hint: probier das mal mit pid=0

Die eigentliche Frage müsste lauten:
Was ist daran richtig?

Erläuter doch z.B. mal deine Absicht hinter grep -v ps...
Jan Novak
2020-11-27 07:28:20 UTC
Permalink
Post by Thomas Noll
Zynisch gesagt: doch.
Dann sei mal nicht zynisch!
Post by Thomas Noll
Post by Jan Novak
Was ist daran falsch
[ "$(ps ax|grep $pid|grep -v ps)" ]
die pid aus einer Datei zu lesen (mit cat Datei, nicht grep)und diese
dann in der Prozess Liste zu suchen?
Etwas hat Stefan dir doch schon geschrieben.
additional hint: probier das mal mit pid=0
*WARUM* sollte ich das tun?
Pid war, ist und wird nie 0 sein!
Post by Thomas Noll
Was ist daran richtig?
Erläuter doch z.B. mal deine Absicht hinter grep -v ps...
du müsstest doch wiessen, was "grep -v ps" bedeutet, oder nicht?


Jan
Juergen Ilse
2020-11-27 09:25:46 UTC
Permalink
Hallo,
Post by Jan Novak
Post by Thomas Noll
Zynisch gesagt: doch.
Dann sei mal nicht zynisch!
Post by Thomas Noll
Post by Jan Novak
Was ist daran falsch
[ "$(ps ax|grep $pid|grep -v ps)" ]
die pid aus einer Datei zu lesen (mit cat Datei, nicht grep)und diese
dann in der Prozess Liste zu suchen?
Etwas hat Stefan dir doch schon geschrieben.
additional hint: probier das mal mit pid=0
*WARUM* sollte ich das tun?
Pid war, ist und wird nie 0 sein!
Post by Thomas Noll
Was ist daran richtig?
Erläuter doch z.B. mal deine Absicht hinter grep -v ps...
du müsstest doch wiessen, was "grep -v ps" bedeutet, oder nicht?
Zum einen kann dir das erheblich mehr als das Kommando "ps" herausfischen
("ps" kommt z.B. auch im Wort "Schnaps" vor, und wie kannst du sicher sein,
dass dieses Wort oder ein andrres "ps" enthaltendes Wort irgendwo in einem
Kommandozeilenargument vorkommt?), zum anderen ist es ohnehin eine daemliche
Methode, im Nachhinein den suchenden Prozess, der sich selbst findet, wieder
aus der Liste der Funde ausschliesen zu wollen: es ist fehlertraeechtig und
unnoetig.

Statt dessen sollte man einen Suchbegriff verwenden, der moeglichst genau die
spezifischen Teile des gesuchten Prozesses aber nicht sich selbst matched.

Um z.B. kein das "grep" Kommando nicht selbst herausfischen zu muessen,
hilft es, einen Suchbegriff zu verwenden, der sich nicht sebst matched.
Sucht man nach "ps", koennte man als Sucbhbegriff z.B. die regular expression
"[p]s" verwenden. Um nicht mit "ps" auch alle Worte zu finden, in denen "ps"
mittendrin als Zeichenkette vorkommt, koennte man nach "[ /][p]s " suchen.
Dam,it hat man zwar immer noch nicht die Faelle erschlkagen, in denen "ps"
als separates Kommandozeilenargument vorkommt, aber zumindest erhaelt man
schon viel weniger "unerwuenschten Beifang" ...
Die Methode, im nachhinein den Prozesse herausfiltern zu wollen, die man
zur Suche nach den Prozessen verwendet hat, halte ich persoenlich eher fuer
*sehr* schlechten Stil, weil man sich potentielle aber vermeidbare Probleme
einhandelt. Wenn man den ganzen Schmuh nicht selbst mittels "grep" aus der
Prozessliste herausfischen will, sollte man auch ueber Kommandos wie "pgrep"
und "pkill" nachdenken, die einem eine Menge der potentiellen Probleme des
"selbstheraussuchens und ausschneidens der PID" vom Hals schafft.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
matched
Rupert Haselbeck
2020-11-26 09:50:04 UTC
Permalink
Post by Jan Novak
Was ist daran falsch
[ "$(ps ax|grep $pid|grep -v ps)" ]
die pid aus einer Datei zu lesen (mit cat Datei, nicht grep)und diese
dann in der Prozess Liste zu suchen?
Dieser Einzeiler findet in der Prozeßliste etwas zu viel. Stell dir vor, es
gibt beispielsweise einen Prozeß mit PID 823 und es gibt einen Prozeß mit
PID 18234. Es genügt für eine Falschausgabe natürlich auch, wenn sich die
Zeichenfolge der gesuchten PID in einem anderen Teil der Ausgabe von ps
findet.
Beispiel:
| ps -ax | grep 72
erzeugt hier gerade 44 Ausgabezeilen mit allem möglichen Zeug, aber nicht
einer PID mit 72.

Beschränkt man die Ausgabe von ps auf die PID, dann ist das immer noch wenig
hilfreich:
| ps -ax -o pid | grep 72
erzeugt hier gerade:
| 72
| 722
| 725
| 1072
| 1272
| 1372
| 2672
| 2724

Wenn du nur wissen willst, ob ein Prozeß mit bekannter PID in der ps-Ausgabe
zu finden ist, dann reduziere die Ausgabe von ps entsprechend oder, besser,
folge dem Hinweis zur Verwendung des kill-Kommandos für diesen Zweck. Dann
kannst du dir auch den, hier ohnehin wenig hilfreichen, zusätzlichen grep-
Aufruf zum Wegwerfen des "grep" selbst sparen

MfG
Rupert
Jan Novak
2020-11-26 10:51:34 UTC
Permalink
Post by Rupert Haselbeck
Beschränkt man die Ausgabe von ps auf die PID, dann ist das immer noch wenig
| ps -ax -o pid | grep 72
| 72
| 722
| 725
| 1072
| 1272
| 1372
| 2672
| 2724
Wenn du nur wissen willst, ob ein Prozeß mit bekannter PID in der ps-Ausgabe
zu finden ist, dann reduziere die Ausgabe von ps entsprechend oder, besser,
folge dem Hinweis zur Verwendung des kill-Kommandos für diesen Zweck. Dann
kannst du dir auch den, hier ohnehin wenig hilfreichen, zusätzlichen grep-
Aufruf zum Wegwerfen des "grep" selbst sparen
Ja, nachvollziehbar. Auf dem besagtem System läuft zunächst "nur" das
Basissystem und der rsync. Somit ist der Fall unwahrscheinlich - aber -
wie du korrekt schreibst, nicht unmöglich und somit werde ich es anders
abfragen (vermutlich mit dem direkten kill).

Mir ging es um die Aussage, ich würde in "/var/run/ wild herum greppen",
was nicht korrekt ist. Dass ich mit meinem grep auf der Prozessliste
auch Ausgaben bekommen könnte, die gar nicht gewünscht sind (so wie von
dir oben beschrieben), ist ein ganz anderes Thema.
Danke für den Hinweis.

Jan
Juergen Ilse
2020-11-24 11:34:44 UTC
Permalink
Hallo,
Post by Jan Novak
auf einem Server werden zu verschiedenen Zeiten mit verschiedenen (bash)
scripten mehrere rsyncs (nacheinander) gestartet.
Mit entsprechnenden PID Mechanismen, kann ich das aufgerufene Script
zwar extern beenden, jedoch wird dann immer noch der nächste rsync im
script gestartet, was nicht gewünscht ist.
Ein "killall rsync" geht auch nicht, weil andere rsyncs, aus anderen
scripten, weiter laufen sollen.
Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?
Ungetestete Idee: Fange den Kill mittels "trap" Kommando im script ab, und
lass dein Script vor der Beendigung zuerst seinen parent ($PPID) killen ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Jan Novak
2020-11-25 10:12:29 UTC
Permalink
Post by Jan Novak
Hallo,
Post by Jan Novak
auf einem Server werden zu verschiedenen Zeiten mit verschiedenen (bash)
scripten mehrere rsyncs (nacheinander) gestartet.
Mit entsprechnenden PID Mechanismen, kann ich das aufgerufene Script
zwar extern beenden, jedoch wird dann immer noch der nächste rsync im
script gestartet, was nicht gewünscht ist.
Ein "killall rsync" geht auch nicht, weil andere rsyncs, aus anderen
scripten, weiter laufen sollen.
Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?
Ungetestete Idee: Fange den Kill mittels "trap" Kommando im script ab, und
lass dein Script vor der Beendigung zuerst seinen parent ($PPID) killen ...
Sehr gute Idee. Diese bedarf zwar noch einiges an (script-) Testsm aber
eine Möglichkeit. Danke!

Jan
Juergen Ilse
2020-11-25 11:12:56 UTC
Permalink
Hallo,
Post by Jan Novak
Post by Juergen Ilse
Post by Jan Novak
auf einem Server werden zu verschiedenen Zeiten mit verschiedenen (bash)
scripten mehrere rsyncs (nacheinander) gestartet.
Mit entsprechnenden PID Mechanismen, kann ich das aufgerufene Script
zwar extern beenden, jedoch wird dann immer noch der nächste rsync im
script gestartet, was nicht gewünscht ist.
Ein "killall rsync" geht auch nicht, weil andere rsyncs, aus anderen
scripten, weiter laufen sollen.
Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?
Ungetestete Idee: Fange den Kill mittels "trap" Kommando im script ab, und
lass dein Script vor der Beendigung zuerst seinen parent ($PPID) killen ...
Sehr gute Idee. Diese bedarf zwar noch einiges an (script-) Testsm aber
eine Möglichkeit. Danke!
Eben nichts konkret getestetes, sondern nur eine erste Idee, die moeglicher-
weise ein Ansatz sein koennte ... Eigentlich sollten die child-prozesse
des aufrufenden scripts ein signal abbekommen, dass sie terminieren laesst,
solange sie nicht von ihrem parent "abgekopelt" sind. Also sollte das killen
des aufrufenden scripts (dessen PID du in der Environment-Variablen PPID
stehen hast) eigentlich ein moeglicher Loesungsansatz sein. Er wird aller-
dings bei einem "kill -9" nicht helfen, da sich dieses auch durch ein "trap"
Kommando in einem script meines Wissens nach nicht abfangen laesst ...
Lass uns bitte wissen, ob es funktioniert hat.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Jan Novak
2020-11-25 14:56:31 UTC
Permalink
Post by Juergen Ilse
Post by Jan Novak
Sehr gute Idee. Diese bedarf zwar noch einiges an (script-) Testsm aber
eine Möglichkeit. Danke!
Eben nichts konkret getestetes, sondern nur eine erste Idee, die moeglicher-
weise ein Ansatz sein koennte ... Eigentlich sollten die child-prozesse
des aufrufenden scripts ein signal abbekommen, dass sie terminieren laesst,
solange sie nicht von ihrem parent "abgekopelt" sind. Also sollte das killen
des aufrufenden scripts (dessen PID du in der Environment-Variablen PPID
stehen hast) eigentlich ein moeglicher Loesungsansatz sein. Er wird aller-
dings bei einem "kill -9" nicht helfen, da sich dieses auch durch ein "trap"
Kommando in einem script meines Wissens nach nicht abfangen laesst ...
Lass uns bitte wissen, ob es funktioniert hat.
Ich denke, dass es genau daran liegt. Ich teste das in den nächsten Tagen.

Jan
Stefan Reuther
2020-11-24 17:23:58 UTC
Permalink
Post by Jan Novak
Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?
Irgendwie vermisse ich hier den naheliegenden Ansatz: "kille das Script,
nicht den rsync". Killen des Scripts reißt den rsync mit weg und startet
natürlich auch den nächsten nicht.

(Funktioniert zumindest mit händisch gestartetem Script. Sonst evtl. mal
in die Richtung Job Control / 'set -m' schauen.)

(Und wenn wir bei 'set' unterwegs sind: 'set -e' bricht das Skript ab,
sobald ein Kommando fehlschlägt, z.B. das extern getötete rsync.)


Stefan
Jan Novak
2020-11-25 10:11:33 UTC
Permalink
Post by Stefan Reuther
Post by Jan Novak
Meine Frage lautet also, wie kann ich ein Script beenden und alle
weiteren darin enthaltenen rsync aufrufe beenden/abbrechen/gar nicht
erst starten lassen?
Irgendwie vermisse ich hier den naheliegenden Ansatz: "kille das Script,
nicht den rsync". Killen des Scripts reißt den rsync mit weg und startet
natürlich auch den nächsten nicht.
Aber genau das mache ich. Das Script schreibt seinen PID (den des
scriptes, nicht den von rsync) in die pid Datei, welcher letztendlich
zum auslesen und killen genutzt werden soll.
Post by Stefan Reuther
(Funktioniert zumindest mit händisch gestartetem Script. Sonst evtl. mal
in die Richtung Job Control / 'set -m' schauen.)
ok.
Post by Stefan Reuther
(Und wenn wir bei 'set' unterwegs sind: 'set -e' bricht das Skript ab,
sobald ein Kommando fehlschlägt, z.B. das extern getötete rsync.)
guter Tip. Hatte ich gar nicht dran gedacht.


Jan
Jan Novak
2020-11-25 10:38:25 UTC
Permalink
Post by Stefan Reuther
(Und wenn wir bei 'set' unterwegs sind: 'set -e' bricht das Skript ab,
sobald ein Kommando fehlschlägt, z.B. das extern getötete rsync.)
Verständnisfehler:
Nicht das rsync wird gekillt, sondern das Script, welches die rsync's
nacheinander starten würde.
Und genau dann passiert es, dass - obwohl das script bereits ge'kill't
wurde, der nachfolgende rsync des gekilltem scriptes dennoch aufgerufen
wird.
Genau dies möchte ich verhindern.

Jan
Juergen Ilse
2020-11-25 11:23:20 UTC
Permalink
Hallo,
Post by Jan Novak
Post by Stefan Reuther
(Und wenn wir bei 'set' unterwegs sind: 'set -e' bricht das Skript ab,
sobald ein Kommando fehlschlägt, z.B. das extern getötete rsync.)
Nicht das rsync wird gekillt, sondern das Script, welches die rsync's
nacheinander starten würde.
Und genau dann passiert es, dass - obwohl das script bereits ge'kill't
wurde, der nachfolgende rsync des gekilltem scriptes dennoch aufgerufen
wird.
Das glaube ich irgendwie nicht so ganz. Ein gekilltes script kann nichts
mehr starten. Bist du sicher, dass du das richtige script gekillt hast?
Ich ging davon aus, dass das script, von dem aus alles gestartet wird,
weitere scripts mit den rsync-kommandos startet. Wenn du von denen eins
killst, geht die Kontrolle an das aufrufende script zurueck, und dieses
startet den naechsten subprocess. Deswegen mein Hinweis, nicht das ent-
sprechende rsync-script, sondern desse parent, das alles aufrufende script,
zu killen. Ich denke, dass dessen schild dann ein HUP abbekommen, dass sie
(sofern sie das nicht abfangen) zum terminieren bringen muesste, und das
uebergeordnete script wird keine neuen rsync-scripts mehr starten, weil es
bereits tot ist. Die PID des aufrufenden Prozesses hast du bei shellscripts
normalerweise in der Environment-Variablen PPID vorliegen.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Jan Novak
2020-11-25 15:02:12 UTC
Permalink
Post by Jan Novak
Hallo,
Post by Jan Novak
Post by Stefan Reuther
(Und wenn wir bei 'set' unterwegs sind: 'set -e' bricht das Skript ab,
sobald ein Kommando fehlschlägt, z.B. das extern getötete rsync.)
Nicht das rsync wird gekillt, sondern das Script, welches die rsync's
nacheinander starten würde.
Und genau dann passiert es, dass - obwohl das script bereits ge'kill't
wurde, der nachfolgende rsync des gekilltem scriptes dennoch aufgerufen
wird.
Das glaube ich irgendwie nicht so ganz. Ein gekilltes script kann nichts
mehr starten. Bist du sicher, dass du das richtige script gekillt hast?
Ich ging davon aus, dass das script, von dem aus alles gestartet wird,
weitere scripts mit den rsync-kommandos startet.
Nein. Das script ruft mehrere rsync befehle auf - keine weiteren
scripte. Die rsyncs werden alle nacheinander aufgerufen - und *nicht* in
den hintergrund geforkt. Somit läuft das script quasi so lange, bis der
letzte rsync Prozess beendet wird. Nach dem Killen des scriptes über
seine pid, bleibt immer ein rsync prozess am laufen. Kille ich den mit
killall erscheint meistens noch einer, welchen ich ebenfalls killen muss.
Für mich sieht es so aus, dass das Script alle rsync Befehle noch
nacheinander absendet, obwohl das eigentliche Script gar nicht mehr da ist.
Noch zu info: die Umgebung ist ein debian buster mit der bash shell.


Jan
Helmut Waitzmann
2020-11-25 14:02:48 UTC
Permalink
Post by Stefan Reuther
Post by Jan Novak
Meine Frage lautet also, wie kann ich ein Script beenden und
alle weiteren darin enthaltenen rsync aufrufe
beenden/abbrechen/gar nicht erst starten lassen?
Irgendwie vermisse ich hier den naheliegenden Ansatz: "kille das
Script, nicht den rsync".
In die Richtung würde ich auch gehen. 
Post by Stefan Reuther
Killen des Scripts reißt den rsync mit weg
Das allerdings stimmt nicht, jedenfalls nicht automatisch von
vorne herein:  Ein Prozess, der aufgrund eines empfangenen Signals
beendet wird, tötet seine Kinder nicht grundsätzlich, sondern
lässt sie als Waisen zurück. 

Man könnte aber hergehen und dem Prozess einen Signalbehandler
beispielsweise für das TERM‐, INT‐ und QUIT‐Signal verpassen:
einen Signalbehandler, der dem Kind ein entsprechendes Signal
schickt, dann den Signalbehandler auf SIG_DFL zurückstellt und ein
entsprechendes Signal auch noch an sich selbst schickt. 

Oder man nutzt Prozessgruppen (job groups, wie Du unten andeutest)
und schickt das ursprüngliche Signal nicht an den Skript‐Prozess
sondern an die Prozessgruppe, der der Skript‐Prozess mitsamt
seinem «rsync»‐Prozess angehört:  Dann kommt das Signal sowohl
beim Skript als auch beim «rsync»‐Prozess an.  Das erfordert
allerdings – wenn man Kollateralschäden vermeiden will –, dass das
Skript in einer eigenen Prozessgruppe gestartet wird. 

Das ist bei modernen Shells in interaktiver Betriebsart der Fall,
wenn das Skript als interaktives Kommando gestartet wird. 

In nicht‐interaktiver Betriebsart machen das Shells (zumindest
ohne besondere Aufforderung dazu) aber nicht.  (Aber siehe dazu
unten «set -m».) 

Probiere das mit folgendem Shell‐Skript aus:


#!/bin/sh
exec ps -o pgid=Job-Gruppe -o pid=Prozessnummer -o args -p "$$"

Falls das Skript in einer eigenen Job‐Gruppe läuft, enthalten die
Spalten «Job-Gruppe» und «Prozessnummer» dieselbe Zahl;
anderenfalls nicht. 
Post by Stefan Reuther
und startet natürlich auch den nächsten nicht.
(Funktioniert zumindest mit händisch gestartetem Script.
Händisch gestartet bedeutet:  Der das Skript startende Shell ist
in der interaktiven Betriebsart.  => Job Control ist aktiviert. 
Post by Stefan Reuther
Sonst evtl. mal in die Richtung Job Control / 'set -m' schauen.)
(Im Shell‐Manual‐Page.) 
Juergen Ilse
2020-11-25 14:47:32 UTC
Permalink
Hallo,
Post by Helmut Waitzmann
Post by Stefan Reuther
Killen des Scripts reißt den rsync mit weg
Das allerdings stimmt nicht, jedenfalls nicht automatisch von
vorne herein:  Ein Prozess, der aufgrund eines empfangenen Signals
beendet wird, tötet seine Kinder nicht grundsätzlich, sondern
lässt sie als Waisen zurück. 
Die Children bekommen ein Signal, sofern der Parent sie nicht bereits hat
"verwaisen" lassen (z.B. mittels "nohup" oder in der bash mittels "disown"
von Hintergrundprozessen). Ich bin mir im Moment allerdings nicht sicher,
welches Signal die Children bekommen (moeglicherweise ein HUP, aber die
Default-Reaktion darauf sollte eigentlich auch "Selbstbeendigung" sein).

Gerade noch mal schnell nesucht: Ja, es ist SIGHUP:
-----------------------
Are you ignoring SIGHUP or daemonizing by escaping the session group ? If so, your process won’t be killed with the others. Make sure you aren’t doing neither.

If your process is somehow being created in another process group for some unavoidable reason, then you’ll need to use non portable Linux extensions to detect that the parent died:

prctl(PR_GET_PDEATHSIG, &sig);
signal(sig, on_parent_killed);
-----------------------
Quelle: https://www.reddit.com/r/C_Programming/comments/jykfyx/program_not_dying_when_the_parent_dies/

Es ist fuer ein script auch nicht notwendig, sich selbst zu killen, wenn es
sich auch ganz einfach mit "exit" mit weniger Aufwand selbst beenden kann ...

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
Helmut Waitzmann
2020-11-25 21:42:40 UTC
Permalink
Post by Juergen Ilse
Post by Helmut Waitzmann
Post by Stefan Reuther
Killen des Scripts reißt den rsync mit weg
Das allerdings stimmt nicht, jedenfalls nicht automatisch von
vorne herein:  Ein Prozess, der aufgrund eines empfangenen
Signals beendet wird, tötet seine Kinder nicht grundsätzlich,
sondern lässt sie als Waisen zurück. 
Die Children bekommen ein Signal, sofern der Parent sie nicht
bereits hat "verwaisen" lassen (z.B. mittels "nohup" oder in der
bash mittels "disown" von Hintergrundprozessen).
Das ist eine Spezialität des Bash, wenn er interaktiv läuft, siehe
Handbuch bash(1) und kein Standardverhalten des Linux‐Kerns:

The shell exits by default upon receipt of a SIGHUP. Before
exiting, an interactive shell resends the SIGHUP to all jobs,
running or stopped. Stopped jobs are sent SIGCONT to ensure that
they receive the SIGHUP. To prevent the shell from sending the
signal to a particular job, it should be removed from the jobs
table with the disown builtin (see SHELL BUILTIN COMMANDS below)
or marked to not receive SIGHUP using disown -h.

If the huponexit shell option has been set with shopt, bash
sends a SIGHUP to all jobs when an interactive login shell
exits.
Post by Juergen Ilse
Ich bin mir im Moment allerdings nicht sicher, welches Signal die
Children bekommen (moeglicherweise ein HUP, aber die
Default-Reaktion darauf sollte eigentlich auch "Selbstbeendigung" sein).
-----------------------
Are you ignoring SIGHUP or daemonizing by escaping the session
group ? If so, your process won’t be killed with the others. Make
sure you aren’t doing neither.
If your process is somehow being created in another process group
for some unavoidable reason, then you’ll need to use non portable
prctl(PR_GET_PDEATHSIG, &sig);
signal(sig, on_parent_killed);
-----------------------
https://www.reddit.com/r/C_Programming/comments/jykfyx/program_not_dying_when_the_parent_dies/
Ich schlage vor, Du probierst es lieber aus, als diesem Forum zu
glauben, bei dem die Ausgangslage nicht genau ermittelt wurde, und
bei dem auf linux‐spezifische Mittel zurückgegriffen wird, die im
Shell nicht verfügbar sind, weil es keine entsprechenden
Builtin‐Commands dafür gibt. 

Nimm Dir dazu ein Terminal mit einem darin laufenden interaktiven
Shell her und starte darin die folgenden Kommandos:

# Schalte im Terminaltreiber das TTOU‐Signal ab, damit
# Hintergrundprozesse aufs Terminal schreiben duerfen:
stty -tostop

sh -c -- '
{ sleep -- 2 &&
printf %s\\n '\''Ich bin das Kind.'\''
} &
printf %s\\n '\''Ich bin der Vater.'\''
kill -s TERM -- "$$"' sh

Deiner Meinung nach hätte sich der Kindprozess (spätestens,
nachdem das Sleep‐Kommando beendet war) mitbeenden sollen, wenn
der Vaterprozess, vom Signal getroffen, beendet wird.  Trotzdem
erhältst Du nach 2 Sekunden noch eine Ausgabe.  Wie erklärst Du
Dir das?
Post by Juergen Ilse
Es ist fuer ein script auch nicht notwendig, sich selbst zu
killen, wenn es sich auch ganz einfach mit "exit" mit weniger
Aufwand selbst beenden kann ...
Du hast den Witz am Selbstmord durch Signalverschickung an sich
selbst nicht verstanden:  Auf diese Weise kommt das Skript genau
so – also mit genau dem exit status – zu Ende, als wenn es von
vorne herein keinen Signalbehandler eingerichtet gehabt hätte, und
der Prozess, der es gestartet hat (beispielsweise Cron), kann das
bemerken und beispielsweise die Fehlermeldung «wurde durch das
TERM‐Signal beendet» per E‐Mail verschicken. 

Das ist für Prozesse, die bei Empfang eines bestimmten Signals
zunächst noch etwas aufräumen wollen, danach aber der Intention
des Signals folgen wollen, eigentlich best practice, nach dem
Aufräumen den Signalbehandler auf SIG_DFL zurückzustellen und sich
das Signal selbst zu schicken. 
--
Hat man erst verstanden, wie Unix funktioniert, ist auch
das Shell-Handbuch kein Buch mit sieben Siegeln mehr.
Jan Novak
2020-11-26 11:03:55 UTC
Permalink
Post by Helmut Waitzmann
Ich schlage vor, Du probierst es lieber aus, als diesem Forum zu
glauben,
...
Post by Helmut Waitzmann
 # Schalte im Terminaltreiber das TTOU‐Signal ab, damit
 stty -tostop
 sh -c -- '
   { sleep -- 2 &&
     printf %s\\n '\''Ich bin das Kind.'\''
   } &
   printf %s\\n '\''Ich bin der Vater.'\''
   kill -s TERM -- "$$"' sh
Deiner Meinung nach hätte sich der Kindprozess (spätestens, nachdem das
Sleep‐Kommando beendet war) mitbeenden sollen, wenn der Vaterprozess,
vom Signal getroffen, beendet wird.  Trotzdem erhältst Du nach 2
Sekunden noch eine Ausgabe.  Wie erklärst Du Dir das?
Korrekt, kann ich hier genauso nachvollziehen.
Post by Helmut Waitzmann
Post by Juergen Ilse
Es ist fuer ein script auch nicht notwendig, sich selbst zu killen,
wenn es sich auch ganz einfach mit "exit" mit weniger Aufwand selbst
beenden kann ...
Mein Wunsch ist es, dass dieses Script gestoppt werden soll, wenn es
manuell notwendig ist - also jemand entscheidet, die rsync's in diesem
script sollen "jetzt" beenden werden. Somit müsste man dem Script die
Info senden, es soll sich und alle aktuell gestarteten rsync (sub- ?)
Prozesse beenden *und* keinen weiteren mehr aufrufen sofern noch einer
folgen würde.

Jan
Jan Novak
2020-11-25 15:06:00 UTC
Permalink
Post by Stefan Reuther
Killen des Scripts reißt den rsync mit weg
Das allerdings stimmt nicht, jedenfalls nicht automatisch von vorne
herein:  Ein Prozess, der aufgrund eines empfangenen Signals beendet
wird, tötet seine Kinder nicht grundsätzlich, sondern lässt sie als
Waisen zurück.
Man könnte aber hergehen und dem Prozess einen Signalbehandler
beispielsweise für das TERM‐, INT‐ und QUIT‐Signal verpassen: einen
Signalbehandler, der dem Kind ein entsprechendes Signal schickt, dann
den Signalbehandler auf SIG_DFL zurückstellt und ein entsprechendes
Signal auch noch an sich selbst schickt.
Aha... das scheint hier der Fall zu sein.
Oder man nutzt Prozessgruppen (job groups, wie Du unten andeutest) und
schickt das ursprüngliche Signal nicht an den Skript‐Prozess sondern an
die Prozessgruppe, der der Skript‐Prozess mitsamt seinem «rsync»‐Prozess
angehört:  Dann kommt das Signal sowohl beim Skript als auch beim
«rsync»‐Prozess an.  Das erfordert allerdings – wenn man
Kollateralschäden vermeiden will –, dass das Skript in einer eigenen
Prozessgruppe gestartet wird.
ok... ist für mich völliges Neuland.
Das ist bei modernen Shells in interaktiver Betriebsart der Fall, wenn
das Skript als interaktives Kommando gestartet wird.
  #!/bin/sh
  exec ps -o pgid=Job-Gruppe -o pid=Prozessnummer -o args -p "$$"
Das heisst, ein set -m in obigem Beispiel würde nicht schaden, da das
Script vom cron gestartet wird?


Jan
Helmut Waitzmann
2020-11-27 01:02:56 UTC
Permalink
Post by Jan Novak
Ein Prozess, der aufgrund eines empfangenen Signals beendet
wird, tötet seine Kinder nicht grundsätzlich, sondern lässt sie
als Waisen zurück.
Man könnte aber hergehen und dem Prozess einen Signalbehandler
einen Signalbehandler, der dem Kind ein entsprechendes Signal
schickt, dann den Signalbehandler auf SIG_DFL zurückstellt und
ein entsprechendes Signal auch noch an sich selbst schickt.
Aha... das scheint hier der Fall zu sein.
Falls Du das auf den ersten Abschnitt bezogen haben willst, stimme
ich zu. 

Das im zweiten Abschnitt Beschriebene geschieht nur dann, wenn man
es im Skript programmierst; von selbst geschieht es nicht:

for signal in HUP INT QUIT TERM PIPE
do
# Richte den Signalbehandler fuer das Signal "$signal" ein:
trap -- 'kill -s '"$signal"' -- '"$pid"'
trap -- - '"$signal"'
kill -s '"$signal"' -- '"$$"
done
Helmut Waitzmann
2020-11-27 16:45:56 UTC
Permalink
Post by Jan Novak
Post by Helmut Waitzmann
Oder man nutzt Prozessgruppen (job groups, wie Du unten
andeutest) und schickt das ursprüngliche Signal nicht an den
Skript‐Prozess sondern an die Prozessgruppe, der der
Skript‐Prozess mitsamt seinem «rsync»‐Prozess angehört:  Dann
kommt das Signal sowohl beim Skript als auch beim
«rsync»‐Prozess an.  Das erfordert allerdings – wenn man
Kollateralschäden vermeiden will –, dass das Skript in einer
eigenen Prozessgruppe gestartet wird.
ok... ist für mich völliges Neuland.
Als Einstieg schau mal im Handbuch credentials(7) nach den
Abschnitten «Process ID» und «Process group ID and session ID» und
im Bash‐Handbuch nach dem Abschnitt «JOB CONTROL». 

Ganz kurz: 


Jeder Prozess hat eine eigene Nummer (process id, pid).  Solange
dieser Prozess lebt oder zwar gestorben, aber noch nicht begraben
ist, hat kein anderer Prozess dieselbe Nummer. 

Er gehört genau einer Prozessgruppe, auch Job genannt, an.  Die
Prozessgruppe hat eine eigene Nummer (process group id, pgid). 
Solange Prozesse in dieser Prozessgruppe leben oder zwar
gestorben, aber noch nicht begraben sind, hat keine andere
Prozessgruppe dieselbe Nummer.  Zu einer Prozessgruppe kann mehr
als ein Prozess gehören. 

Eine Prozessgruppe wird erzeugt, indem ein Prozess den
Betriebssystemkern bittet, ihn aus seiner bisherigen Prozessgruppe
herauszunehmen und in eine neue, frisch erzeugte zu stecken.  Die
neue Prozessgruppe bekommt die Nummer des Prozesses als
Gruppennummer.  => Die Prozessgruppennummer des Prozesses ist
jetzt gleich seiner Prozessnummer.  Man nennt den Prozess jetzt
Prozessgruppenführer (process group leader, job group leader). 

Jede Prozessgruppe (und damit alle Prozesse der Gruppe ebenfalls)
gehört einer Sitzung an.  Die Sitzung hat eine eigene Nummer
(session id, sid).  Solange Prozesse in dieser Sitzung leben oder
zwar gestorben, aber noch nicht begraben sind, hat keine andere
Sitzung dieselbe Nummer.  Zu einer Sitzung kann mehr als eine
Prozessgruppe gehören. 

Eine Sitzung wird erzeugt, indem ein Prozess den
Betriebssystemkern bittet, ihn aus seiner bisherigen Prozessgruppe
und Sitzung herauszunehmen und in eine neue, frisch erzeugte
Prozessgruppe und Sitzung zu stecken.  Die neue Prozessgruppe und
Sitzung erhalten jeweils die Nummer des Prozesses als Gruppen‐
bzw. Sitzungsnummer.  => Die Prozessgruppen‐ und die
Sitzungsnummer des Prozesses sind jetzt gleich seiner
Prozessnummer.  Man nennt den Prozess jetzt Sitzungsführer
(session leader). 

Ein Terminal nennt man Steuerterminal (controlling terminal), wenn
es gewissen Prozessen (s. u.) auf Tastendruck Job‐Control‐Signale,
wie beispielsweise ein INT‐ (interrupt) oder ein TSTP‐ (terminal
stop) Signal schicken kann.  Dadurch können Prozesse auf
Tastendruck abgebrochen oder angehalten werden.  Welche Prozesse
die Adressaten dieser Signale sind, wird durch die Zuordnung des
Steuerterminals zu genau einer Sitzung und genau einer
Prozessgruppe festgelegt: 

Der Betriebssystemkern vermerkt bei jedem Steuerterminal die
Nummer der Sitzung, zu der es gehört.  Außerdem vermerkt er bei
dem Terminal eine Prozessgruppe, die zur Sitzung gehört.  Die
Prozesse in dieser Gruppe erhalten die Signale, die das Terminal
auf Tastendruck verschickt.  Man sagt, diese Prozessgruppe «läuft
im Vordergrund». 

Umgekehrt ist jede Sitzung höchstens einem Steuerterminal
zugeordnet.  (Es gibt also auch Sitzungen ohne Steuerterminal.) 

Beispiel:

Im Steuerterminal /dev/pts/12 läuft ein interaktiver «bash».  Dort
hat man das Kommando

COLUMNS=60 ps -o ppid -o sid -o pgid -o pid -o tpgid -o stat \
-o args 2>&1 |
less

eingetippt und sieht im Terminal in der Ausgabe von «less» jetzt
folgendes:

PPID SID PGID PID TPGID TT STAT COMMAND
12345 12345 23456 23456 23456 pts/12 R+ ps -o ppid -o si
12345 12345 23456 2468 23456 pts/12 S+ less
32724 12345 12345 12345 23456 pts/12 Ss /usr/bin/bash


Beobachtungen:

Die «less»‐ und «ps»‐Prozesse sind Kindprozesse des
«bash»‐Prozesses:  In der Spalte «PPID» steht bei ihnen die
Prozessnummer des «bash»‐Prozesses. 

Alle 3 Prozesse gehören derselben Sitzung mit der Nummer 12345
(Spalte «SID») an. 

Die 3 Prozesse verteilen sich auf 2 Prozessgruppen (Spalte
«PGID»): 12345 und 23456. 

Alle 3 Prozesse haben «/dev/pts/12» als Steuerterminal (Spalte
«TT»). 

Das Terminal hat im Augenblick die Prozessgruppe 23456 als
Vordergrundprozessgruppe (Spalte «TPGID»).  Die Prozesse der
Vordergrundprozessgruppe sind in der Spalte «STAT» mit einem «+»
gekennzeichnet.  => Im Augenblick läuft das «ps»‐«less»‐Kommando
im Vordergrund. 

Der Sitzungsführer ist der Prozess mit der Nummer 12345
(pid=pgid=sid), «/usr/bin/bash».  Das «s» in der Spalte «STAT»
zeigt die Sitzungsführerschaft an. 

Im Augenblick der Erstellung der Ausgabe lief der «ps»‐Prozess
(das «R» in der Spalte «STAT»).  Die anderen beiden Prozesse
hatten nichts zu tun (das «S» in der Spalte «STAT»). 

(Für die Grafik bitte Festbreitenschrift verwenden:) 


Sitzung 12345
+----------------------+ <-----.
| sid=12345 | \
| terminal=/dev/pts/12 >------. \
| +---------------+ | \ \ Steuerterminal /dev/pts/12
| | pgid=12345 | | `----> +----------------------+
| | +-----------+ | | \ | terminal=/dev/pts/12 |
| | | pid=12345 | | | `-< sid=12345 |
| | +-----------+ | | .-< tpgid=23456 |
| +---------------+ | / +----------------------+
| | /
| +---------------+ <-------------'
| | pgid=23456 | |
| | +-----------+ | |
| | | pid=23456 | | |
| | +-----------+ | |
| | | |
| | +-----------+ | |
| | | pid=2468 | | |
| | +-----------+ | |
| +---------------+ |
+----------------------+

Wenn man jetzt Ctrl‐Z tippt, schickt der Betriebssystemkern ein
TSTP‐Signal an alle Prozesse in der Prozessgruppe, deren
Gruppennummer im Steuerterminal vermerkt (tpgid=23456) ist. 

Dadurch werden die Prozesse der Vordergrundprozessgruppe (also die
Prozesse «less» und – wenn er sich noch nicht beendet hätte –
«ps») gestoppt.  (Dass «less» gestoppt ist, sieht man am «T» in
der Spalte «STAT» in der folgenden Prozessliste.) 

Weil der «less»‐Prozess ein Kind des «bash»‐Prozesses ist (siehe
die Spalte «PPID»), merkt der «bash»‐Prozess, dass der
«less»‐Prozess gestoppt wurde.  Jetzt läuft also kein
Vordergrund‐Job mehr, auf den der «bash»‐Prozess warten müsste. 
Deshalb macht er sich selbst zum Vordergrund‐Job:  Er bittet das
Betriebssystem, die Prozessgruppe im Terminal auf seine
Prozessgruppe, die Prozessgruppe 12345, umzustellen.  Dass das
geschehen ist, sieht man an der Nummer «12345» in der Spalte
«TPGID» und dem «+» in der Spalte «STAT»): 

PPID SID PGID PID TPGID TT STAT COMMAND
12345 12345 23456 2468 12345 pts/12 T less
32724 12345 12345 12345 12345 pts/12 Ss+ /usr/bin/bash

Sitzung 12345
+----------------------+ <-----.
| sid=12345 | \
| terminal=/dev/pts/12 >------. \
| +---------------+ <------. \ \ Steuerterminal /dev/pts/12
| | pgid=12345 | | \ `----> +----------------------+
| | +-----------+ | | \ \ | terminal=/dev/pts/12 |
| | | pid=12345 | | | \ `-< sid=12345 |
| | +-----------+ | | `-------< tpgid=12345 |
| +---------------+ | +----------------------+
| |
| +---------------+ |
| | pgid=23456 | |
| | +-----------+ | |
| | | pid=23456 | | |
| | +-----------+ | |
| | | |
| | +-----------+ | |
| | | pid=2468 | | |
| | +-----------+ | |
| +---------------+ |
+----------------------+
Post by Jan Novak
Das heisst, ein set -m in obigem Beispiel würde nicht schaden, da das
Script vom cron gestartet wird?
Ja.  Dazu müsste im Crontab etwa folgendes stehen:


set -m && hier_der_Aufruf_vom_Skript


Es könnte aber je nach Shell sein, dass «set -m» nichts bewirkt
außer, dass der Shell sich beschwert, dass er kein job control
nutzen kann, weil er kein Steuerterminal hat, denn Cron‐Jobs
laufen ohne Terminal. 


Auf Debian Buster ausprobiert: 


«bash» (egal, ob in der nativen oder der zu POSIX kompatiblen
Betriebsart), startet das Skript in einer neuen Prozessgruppe. 

«dash» beschwert sich «can't access tty; job control turned off»
und startet das Skript, ohne eine neue Prozessgruppe zu erzeugen. 

Es kommt also darauf an, welchem Shell die im crontab enthaltenen
Kommandozeilen zur Ausführung übergeben werden. 
Jan Novak
2020-12-01 10:57:58 UTC
Permalink
(... sehr ausführlich)

Vielen Dank für die Aufklärung (nicht ironisch gemeint).

(... sehr interessante Aufzählungen)
Post by Jan Novak
Das heisst, ein set -m in obigem Beispiel würde nicht schaden, da das
Script vom cron gestartet wird?
korrekt - also dann, wenn es abschließend laufen wird.
  set -m && hier_der_Aufruf_vom_Skript
Ahh... ich dachte, das "set -m" muss im Script stehen.
Es könnte aber je nach Shell sein, dass «set -m» nichts bewirkt außer,
dass der Shell sich beschwert, dass er kein job control nutzen kann,
weil er kein Steuerterminal hat, denn Cron‐Jobs laufen ohne Terminal.
«bash» (egal, ob in der nativen oder der zu POSIX kompatiblen
Betriebsart), startet das Skript in einer neuen Prozessgruppe.
kann ich hier (auch unter debian buster) nachvollziehen.
Es kommt also darauf an, welchem Shell die im crontab enthaltenen
Kommandozeilen zur Ausführung übergeben werden.
In der Regel /bin/bash.

Ich muss jetzt erstmal aus deinen Ausführungen das gewünschte
extrahieren und dann testen.

Nochmals, herzlichen Dank.


Jan
Helmut Waitzmann
2020-12-01 21:33:57 UTC
Permalink
Post by Jan Novak
Post by Jan Novak
Das heisst, ein set -m in obigem Beispiel würde nicht schaden,
da das Script vom cron gestartet wird?
korrekt - also dann, wenn es abschließend laufen wird.
  set -m && hier_der_Aufruf_vom_Skript
Ahh... ich dachte, das "set -m" muss im Script stehen.
Das Ziel soll ja sein, dass nicht das Skript seine «rsync»‐Aufrufe
als je eigenes Job startet, sondern, dass der Crontab‐Shell das
Skript als eigenes Job startet, damit man ein Signal an das
komplette Job, also das Skript mitsamt seinen
«rsync»‐Unterprozessen schicken kann und so alle Prozesse auf
einen Sitz erreicht.  Also muss das «set -m» nicht im Skript
sondern dort stehen, wo das Skript aufgerufen wird. 

Das Schicken eines Signals an ein ganzes Job (also eine
Prozessgruppe) wird im Systemaufruf «kill» so bewerkstelligt, dass
das Negative der Prozessnummer des Prozessgruppenführers angegeben
wird.  Und so hält es auch das «kill»‐Kommando, das nicht viel
mehr als eine einfache Verpackung des Systemaufrufs ist. 

Das in den Shell eingebaute «kill»‐Kommando bietet außerdem an,
die vom Shell vergebenen Job‐Nummern (also die Bezeichnungen «%1»,
«%2», …, «%+» und «%-», siehe im Shell‐Handbuch) anstelle der
Prozessnummern entgegenzunehmen. 
Jan Novak
2020-12-03 06:27:09 UTC
Permalink
Post by Jan Novak
Das heisst, ein set -m in obigem Beispiel würde nicht schaden, da
das Script vom cron gestartet wird?
korrekt - also dann, wenn es abschließend  laufen wird.
   set -m && hier_der_Aufruf_vom_Skript
Ahh... ich dachte, das "set -m" muss im Script stehen.
Das Ziel soll ja sein, dass nicht das Skript seine «rsync»‐Aufrufe als
je eigenes Job startet, sondern, dass der Crontab‐Shell das Skript als
eigenes Job startet, damit man ein Signal an das komplette Job, also das
Skript mitsamt seinen «rsync»‐Unterprozessen schicken kann und so alle
Prozesse auf einen Sitz erreicht.  Also muss das «set -m» nicht im
Skript sondern dort stehen, wo das Skript aufgerufen wird.
ahh... verstehe. Das macht es jetzt verständlich.
Vielen Dank für deine Ausführungen.


Jan

Jan Novak
2020-11-26 11:11:38 UTC
Permalink
In nicht‐interaktiver Betriebsart machen das Shells (zumindest ohne
besondere Aufforderung dazu) aber nicht.  (Aber siehe dazu unten «set -m».)
  #!/bin/sh
  exec ps -o pgid=Job-Gruppe -o pid=Prozessnummer -o args -p "$$"
Falls das Skript in einer eigenen Job‐Gruppe läuft, enthalten die
Spalten «Job-Gruppe» und «Prozessnummer» dieselbe Zahl; anderenfalls nicht.
Ich bekomme das hier raus
b-Gruppe Prozessnummer COMMAND
12299 12299 ps -o pgid=Job-Gruppe -o pid=Prozessnummer -o
args -p 12299

und die PID's sind imme rgleich, egal ob "set -m" gesetzt ist oder nicht.


Jan
Lesen Sie weiter auf narkive:
Loading...