Kann jemand im Detail erklären, was "set -m" macht?

16

Auf der Manpage steht nur:

-m Jobsteuerung ist aktiviert.

Aber was heißt das eigentlich?

Ich bin auf diesen Befehl in einer SO-Frage gestoßen . Ich habe dasselbe Problem wie bei OP, nämlich "Fabric kann Tomcat nicht starten". Und das set -mgelöst. Das OP hat ein wenig erklärt, aber ich verstehe nicht ganz:

Das Problem trat im Hintergrund auf, da sie nach Beendigung des Befehls beendet werden.

Die Lösung ist einfach: fügen Sie einfach "set -m" hinzu. Präfix vor Befehl.

laike9m
quelle

Antworten:

10

Zitieren der Bash-Dokumentation (von man bash):

JOB CONTROL
       Job  control  refers to  the  ability  to selectively  stop
       (suspend) the execution of  processes and continue (resume)
       their execution at a later point.  A user typically employs
       this facility via an interactive interface supplied jointly
       by the operating system kernel's terminal driver and bash.

Also, ganz einfach gesagt, mit set -m(der Standard für interaktive Shells) können Sie integrierte Funktionen wie fgund verwenden bg, die unter set +m(der Standard für nicht interaktive Shells) deaktiviert sind.

Mir ist nicht klar, wie die Verbindung zwischen Jobsteuerung und dem Beenden von Hintergrundprozessen beim Beenden aussieht, aber ich kann bestätigen, dass es einen gibt: Beim Ausführen set -m; (sleep 10 ; touch control-on) &wird die Datei erstellt, wenn die Shell direkt nach der Eingabe dieses Befehls beendet set +m; (sleep 10 ; touch control-off) &wird, nicht jedoch.

Ich denke, die Antwort liegt im Rest der Dokumentation für set -m:

-m      Monitor  mode. [...]                     Background pro‐
        cesses run in a separate process group and a  line  con‐
        taining  their exit status is printed upon their comple‐
        tion.

Dies bedeutet, dass Hintergrundjobs, unter set +mdenen gestartet wurde, keine tatsächlichen "Hintergrundprozesse" sind ("Hintergrundprozesse sind Prozesse, deren Prozessgruppen-ID von der des Terminals abweicht"): Sie haben dieselbe Prozessgruppen-ID wie die Shell, von der sie gestartet wurden, und keine eigene Prozessgruppe wie richtige Hintergrundprozesse. Dies erklärt das Verhalten, das beobachtet wird, wenn die Shell vor einigen ihrer Hintergrundjobs beendet wird: Wenn ich richtig verstehe, wird beim Beenden ein Signal an die Prozesse in derselben Prozessgruppe wie die Shell gesendet (wodurch Hintergrundjobs beendet werden, die unter gestartet wurden set +m), jedoch nicht zu denen anderer Prozessgruppen (und damit von wahren Hintergrundprozessen, unter denen begonnen wurde set -m).

In Ihrem Fall startup.shstartet das Skript also vermutlich einen Hintergrundjob. Wenn dieses Skript nicht interaktiv ausgeführt wird, z. B. über SSH, wie in der Frage, mit der Sie verknüpft sind, ist die Jobsteuerung deaktiviert. Der "Hintergrund" -Job teilt sich die Prozessgruppe der Remote-Shell und wird daher abgebrochen, sobald diese Shell beendet wird. Umgekehrt erhält der Hintergrundjob durch Aktivieren der Jobsteuerung in dieser Shell eine eigene Prozessgruppe und wird nicht beendet, wenn die übergeordnete Shell beendet wird.

dhag
quelle
Danke für deine Antwort, aber wie hängt das tomcat/bin/startup.shmit fg/ zusammen bg?
laike9m
1
Es ist nicht direkt verwandt; Ich habe versucht zu antworten "Jobkontrolle ist aktiviert / was bedeutet das eigentlich?" im Allgemeinen. Vielleicht habe ich es nicht klargestellt, aber Ihr Skript scheint einen Hintergrundjob zu starten, worauf sich der Rest meiner Antwort bezieht.
Dhag
2

Ich habe dies auf der Github-Problemliste gefunden und ich denke, dies beantwortet Ihre Frage wirklich.

Es ist nicht wirklich ein SSH-Problem, es ist eher das subtile Verhalten um nicht interaktive / interaktive BASH-Modi und die Signalweitergabe an Prozessgruppen.

Das Folgende basiert auf /programming/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 und http: //www.itp.uzh.ch/~dpotter/howto/daemonize , mit einigen Annahmen, die nicht vollständig validiert sind, aber Tests, wie dies funktioniert, scheinen dies zu bestätigen.

pty / tty = false

Die gestartete Bash-Shell stellt eine Verbindung zu stdout / stderr / stdin des gestarteten Prozesses her und wird solange ausgeführt, bis nichts mehr mit den Sockets verbunden ist und die untergeordneten Elemente beendet wurden. Ein guter Deamon-Prozess stellt sicher, dass nicht darauf gewartet wird, dass die untergeordneten Prozesse beendet werden. In diesem Modus wird von SSH kein SIGHUP an den untergeordneten Prozess gesendet. Ich glaube, dass dies für die meisten Skripte, die einen Prozess ausführen, der die Desaminierung selbst erledigt und nicht im Hintergrund ausgeführt werden muss, korrekt funktioniert. Wenn Init-Skripte '&' zum Hintergrund eines Prozesses verwenden, ist es wahrscheinlich, dass das Hauptproblem darin besteht, ob der Hintergrundprozess jemals versucht, von stdin zu lesen, da dies ein SIGHUP auslöst, wenn die Sitzung beendet wurde.

pty / tty = true *

Wenn das Init-Skript den Prozess im Hintergrund startet, gibt die übergeordnete BASH-Shell einen Exit-Code an die SSH-Verbindung zurück, der sofort beendet wird, da nicht darauf gewartet wird, dass ein untergeordneter Prozess beendet wird, und nicht auf stdout blockiert wird / stderr / stdin. Dadurch wird ein SIGHUP an die übergeordnete Bash-Shell-Prozessgruppe gesendet, die die gerade gestarteten untergeordneten Prozesse enthält, da die Jobsteuerung in Bash im nicht interaktiven Modus deaktiviert ist. Wenn ein Daemon-Prozess beim Forken oder im Fork-Prozess explizit eine neue Prozesssitzung startet, erhalten er oder seine untergeordneten Prozesse das SIGHUP nicht, wenn der übergeordnete BASH-Prozess beendet wird. Beachten Sie, dass dies anders ist als bei unterbrochenen Jobs, bei denen ein SIGTERM angezeigt wird. Ich vermute, die Probleme, die damit verbunden sind, haben manchmal nur mit einer leichten Rennbedingung zu tun. http://www.itp.uzh.ch/~dpotter/howto/daemonize , Sie werden sehen, dass im Code die neue Sitzung durch den Fork-Prozess erstellt wird, der möglicherweise nicht ausgeführt wird, bevor das übergeordnete Programm beendet wird Erfolgs- / Misserfolgsverhalten wie oben erwähnt. Eine Sleep-Anweisung lässt genügend Zeit, damit der Fork-Prozess eine neue Sitzung erstellt, weshalb dies in einigen Fällen funktioniert.

pty / tty = true und die Auftragssteuerung wird in bash explizit aktiviert

SSH stellt keine Verbindung zu stdout / stderr / stdin der Bash-Shell oder zu gestarteten untergeordneten Prozessen her. Dies bedeutet, dass es beendet wird, sobald die übergeordnete Bash-Shell die Ausführung der angeforderten Befehle beendet hat. In diesem Fall werden bei expliziter Aktivierung der Jobsteuerung alle Prozesse, die von der Bash-Shell mit '&' im Hintergrund gestartet werden, sofort in eine separate Sitzung versetzt und erhalten kein SIGHUP-Signal, wenn der übergeordnete Prozess zur BASH-Sitzung beendet wird ( SSH-Verbindung in diesem Fall).

Was ist zu beheben

Ich denke, die Lösungen müssen nur explizit in der run / sudo-Betriebsdokumentation als Sonderfall erwähnt werden, wenn mit Hintergrundprozessen / -diensten gearbeitet wird. Verwenden Sie grundsätzlich entweder 'pty = false' oder aktivieren Sie die Jobsteuerung explizit als ersten Befehl, wenn dies nicht möglich ist. Das Verhalten ist dann korrekt.

Von https://github.com/fabric/fabric/issues/395

pootow
quelle