Ich versuche ein Linux-Shell-Skript (vorzugsweise bash) zu schreiben,
angeblich namens detach.sh
, um Programme sicher von einem Terminal zu trennen,
so dass:
Aufruf: ./detach.sh prog [arg1 arg2 ...]
.
Ist exec
-able, z. indem Sie dies in Ihrer Shell ausführen:
Mit richtiger Quotierung (hauptsächlich mit Argumenten, die Leerzeichen enthalten).
Verwirft die Ausgaben (da sie nicht benötigt werden).
Verwendet nicht screen
, tmux
usw.
(Gleicher Grund mit 4, plus keine Notwendigkeit für einen zusätzlichen Babysitter-Prozess).
Verwendet (einigermaßen) portable Befehle und Programme,
und keine Dinge wie start-stop-daemon
, die ziemlich streuspezifisch sind.
Ich habe mir verschiedene Wege ausgedacht (shebang linien #!/bin/bash
vernachlässigt)
aus Gründen der Kürze):
nohup
:
disown
:
setsid
:
Verwenden einer Untershell:
%Vor% nohup
/ setsid
kombiniert mit subshell:
Wenn Sie gedit
als Testprogramm verwenden (ersetzen Sie den "$@"
-Teil),
Bedingung 1 kann mit allen oben genannten Methoden erfüllt werden,
aber Bedingung 2 kann mit keiner zufrieden sein.
Wenn jedoch ein beliebiges Programm (aber keine eingebaute Shell) an Skript 5 angehängt wird,
alle Bedingungen scheinen erfüllt zu sein (zumindest für mich im Fall gedit
).
Zum Beispiel:
Jeder mit einer Idee über eine Erklärung der oben genannten Phänomene und wie man die Anforderungen richtig umsetzt?
BEARBEITEN:
Mit Bedingung 2, ich meine, das Programm sollte vom Terminal getrennt werden, läuft aber sonst wie gewohnt. Mit dem Fall gedit
zum Beispiel schlägt die Bedingung fehl, wenn gedit
unmittelbar nach Beendigung des Skriptprozesses beendet wird.
Bei näherer Untersuchung wurden diese bisher unbemerkten Fakten aufgedeckt:
Beide Skripte 3 und 5 (nur die setsid
Variante)
erfülle alle Bedingungen, wenn ein /bin/true
an das Skript angehängt ist.
Diese Skripte, wie in der Tat 1 modifiziert, funktionieren auch, wenn
/bin/true
wird durch for i in {0..9999}; do :; done
ersetzt.
Daraus können wir schließen, dass:
(Von Tatsache 1)
Mehrere Ebenen der Ablösung (wie in Skript 5) sind nicht notwendig,
und der Schlüssel ist, das richtige Dienstprogramm zu verwenden ( setsid
).
(Von Tatsache 2)
Eine geeignete Verzögerung vor dem Bash-Exit ist für den Erfolg des Skripts notwendig.
(Der Aufruf des externen Programms /bin/true
benötigt etwas Zeit
genau wie der pure-bash time consumer for i in {0..9999}; do :; done
.)
Ich habe mir den Quellcode nicht angesehen, aber ich schätze eine mögliche Erklärung
Es ist möglich, dass bash beendet wird, bevor setsid
die Ausführung der Konfiguration beendet
Umgebung des Programms zu laufen, wenn eine entsprechende Verzögerung nicht angewendet wird.
Und schließlich sollte eine optimale Lösung
sein %Vor%BEARBEITEN 1 :
Die Notwendigkeit einer Verzögerung wurde hier erläutert. Vielen Dank an @wilx!
BEARBEITEN 2 :
(Dank @MateiDavid) haben wir vergessen, die Standardeingabe umzuleiten, und ein besserer Weg wäre:
%Vor% Sie versuchen einen UNIX-Daemon-Prozess zu erstellen (dh einen Prozess, der kein kontrollierendes Terminal hat und das ist seine eigene Sitzung Führer). Der Befehl setsid
sollte dies für Sie tun, aber Sie sind dafür verantwortlich, alle Dateideskriptoren zu schließen, die auf dem Terminal geöffnet sind, das Sie verlassen. Dies kann erfolgen, indem Sie sie an /dev/null
umleiten oder die Shell-Syntax zum Schließen von Dateideskriptoren verwenden (z. B. 2>&-
und 0<&-
in Bash).