Starten Sie einen Hintergrundprozess von einem Skript aus und verwalten Sie ihn, wenn das Skript endet

15

Ich möchte einen Prozess wie einen Daemon aus einem Skript ausführen und konfigurieren.
Meine Shell ist unter Cygwin zsh emuliert und der Daemon ist SFK , ein einfacher FTP-Server.

Für das, was hier zählt, kann das Skript startserv.shwie folgt verfasst werden:

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
$cmd &

Nachdem das Skript ausgeführt wurde startserv.sh, wird es angehalten (beendet?), Ohne dass eine Eingabeaufforderung angezeigt wird.

  • CTRL+ Cbeendet sowohl das Skript als auch den Hintergrundjobprozess;

  • Wenn Sie Enterdas Skript beenden, bleibt der Vorgang im Hintergrund.

Wie auch immer, ich kann es nur über psund nicht über sehen. jobsWenn ich den Vorgang abschließen möchte, muss ich ein brutales kill -9Signal senden , was ich zu Gunsten von CTRL+ vermeiden möchte C.

Eine Alternative wäre, das gesamte Skript im Hintergrund auszuführen. 'Wäre', aber der readBefehl kann die Benutzereingabe nicht abrufen, wenn das Skript ausgeführt wird als startserv.sh &.

Beachten Sie, dass ich einen kurzlebigen Server benötige, keinen echten Daemon . Das heißt, dass der Serverprozess nach dem Ende des Skripts im Hintergrund ausgeführt werden soll, um einfache interaktive Shell-Aufgaben (mit einem Gast einer virtuellen Maschine) auszuführen. Ich brauche den Prozess, um die Hülle zu überleben. nohupscheint daher nicht angebracht.

antonio
quelle
Rufen Sie die Prozess-ID des Prozesses ab, der im Hintergrund ausgeführt wird, bgproc="$!"und command "$bgproc" ergreifen Sie dann die entsprechende Aktion. Siehe auch stackoverflow.com/questions/1908610/…
Valentin Bajrami
Sie können auch eine PID-Datei erstellen. Lesen Sie dann diese Datei, um zu sehen, um welche Prozessnummer es sich handelt, und gehen Sie von dort aus.
jgr208

Antworten:

18

Wenn Sie Enterdas Skript beenden, bleibt der Vorgang im Hintergrund.

Fast! Tatsächlich wurde das Skript bereits beendet, als Sie auf drücken Enter. Auf diese Weise können Sie jedoch Ihre Eingabeaufforderung zurückerhalten (da Ihre Shell erneut druckt $PS1).

Der Grund, warum das Drücken von Ctrl+ Cbeide beendet, ist, dass die beiden verknüpft sind. Wenn Sie Ihr Skript ausführen, initiiert Ihre Shell eine Subshell, in der Sie es ausführen können. Wenn Sie diese Subshell beenden, stirbt Ihr Hintergrundprozess wahrscheinlich aufgrund eines SIGHUPSignals ab.

Trennen Sie das Skript, den Hintergrundprozess und die Subshell

Mit nohupkönnen Sie diese kleine Unannehmlichkeit vielleicht loswerden.

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

Die disownAlternative

Wenn Sie von /bin/shnach wechseln können /bin/bash, können Sie es auch versuchen disown. Um mehr zu erfahren, geben Sie einfach help disowneine bashInstanz ein.

disown -h $cmd &

Den Hintergrundprozess "schön" beenden

Nun, wenn es darum geht, Ihren Prozess zu beenden, können Sie perfekt ein " Ctrl+ C" verwenden kill. Senden Sie einfach keine brutalen SIGKILL. Stattdessen können Sie Folgendes verwenden:

$ kill -2 [PID]
$ kill -15 [PID]

Welches wird ein nettes SIGINT(2) oder SIGTERM(15) an Ihren Prozess senden . Sie können den PID-Wert auch drucken, nachdem Sie den Vorgang gestartet haben:

...
nohup $cmd &
echo $!

... oder noch besser, lassen Sie das Skript auf ein warten SIGINTund senden Sie es zurück an den Hintergrundprozess (dies wird Ihr Skript jedoch im Vordergrund halten) :

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

# Storing the background process' PID.
bg_pid=$!

# Trapping SIGINTs so we can send them back to $bg_pid.
trap "kill -2 $bg_pid" 2

# In the meantime, wait for $bg_pid to end.
wait $bg_pid

Wenn a SIGINTnicht ausreicht, verwenden Sie SIGTERMstattdessen einfach a (15):

trap "kill -15 $bg_pid" 2 15

Wenn Ihr Skript für den Hintergrundprozess ein SIGINT( Ctrl+ C, kill -2) oder eine SIGTERMWeile empfängt , waitleitet es die Signale einfach an das Skript weiter . Wenn diese Signale die sfkInstanz waitbeenden, kehrt der Aufruf zurück und beendet daher auch Ihr Skript :)

John WH Smith
quelle
1
+1 Sehr informativ. Gibt es eine Möglichkeit, vom Skript auf die Jobtabelle der übergeordneten Shell des Skripts zuzugreifen, da das Skript in einer Subshell ausgeführt wird? Dies ist eine Liste der Jobs, die jobsim Terminal ausgegeben werden, nachdem das Skript beendet wurde (anstatt ps).
Antonio
1
Jobs sind Ihrer aktuellen Shell zugeordnet, sie werden nicht von einer Shell zur anderen übertragen. Wenn Ihre Subshell stirbt, werden ihre Jobs nicht wiederhergestellt. Indem Sie die PID Ihres Hintergrundprozesses drucken, stellen Sie sicher, dass Sie auch nach dem Beenden der Subshell ( pid -p) problemlos Informationen darüber erhalten können .
John WH Smith
nette Erklärung, aber wenn Ihr Skript mehr Befehle enthält, werden sie (wegen der wait) nie ausgeführt . Wenn Sie das Warten
beenden