Lancer un processus d'arrière-plan à partir d'un script et le gérer à la fin du script

15

Je voudrais exécuter et configurer un processus de manière similaire à un démon à partir d'un script.
Mon shell est émulé en zsh sous Cygwin et le démon est SFK , un serveur FTP de base.

Pour ce qui compte ici, le script startserv.shpeut être rédigé comme suit:

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

Après avoir exécuté le script startserv.sh, il s'arrête (se termine?) Sans afficher aucune invite, puis:

  • CTRL+ Ctermine à la fois le script et le processus de tâche en arrière-plan;

  • Frapper Enterle script met fin au processus reste en arrière-plan.

Quoi qu'il en soit, je ne peux le voir que via pset non jobs, donc, quand je veux terminer le processus, je dois envoyer un kill -9signal brutal , ce que j'aimerais éviter en faveur de CTRL+ C.

Une alternative serait d' exécuter l'intégralité du script en arrière-plan. 'Serait', mais la readcommande ne peut pas obtenir l'entrée utilisateur si le script est exécuté en tant que startserv.sh &.

Notez que j'ai besoin d'un serveur éphémère, pas d'un vrai démon : c'est-à-dire que je veux que le processus serveur s'exécute en arrière-plan, une fois le script terminé, pour effectuer de simples tâches de shell interactif (avec un invité de machine virtuelle), mais je ne ' t besoin du processus pour survivre à la coquille; ne nohupsemble donc pas approprié.

antonio
la source
obtenir l'ID de processus du processus s'exécutant en arrière-plan à l'aide de bgproc="$!", puis command "$bgproc" prendre l'action appropriée. Voir aussi stackoverflow.com/questions/1908610/…
Valentin Bajrami
vous pouvez également créer un fichier PID. Ensuite, lisez ce fichier pour voir de quel numéro de processus il s'agit et allez-y.
jgr208

Réponses:

18

Frapper Enterle script met fin au processus reste en arrière-plan.

Presque! En fait, le script est déjà terminé au moment où vous appuyez sur Enter. Cependant, c'est ainsi que vous pouvez récupérer votre invite (car votre shell imprime $PS1à nouveau son intégralité).

La raison pour laquelle le fait d'appuyer sur Ctrl+ Cmet fin aux deux est parce que les deux sont liés. Lorsque vous exécutez votre script, votre shell lance un sous-shell dans lequel l'exécuter. Lorsque vous terminez ce sous-shell, votre processus d'arrière-plan meurt, probablement à cause d'un SIGHUPsignal.

Séparez le script, le processus d'arrière-plan et le sous-shell

En utilisant nohup, vous pourrez peut-être vous débarrasser de ce petit inconvénient.

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

L' disownalternative

Si vous pouvez passer de /bin/shà /bin/bash, vous pouvez également essayer disown. Pour en savoir plus, tapez simplement help disownune bashinstance.

disown -h $cmd &

Tuer le processus d'arrière-plan "bien"

Maintenant, quand il s'agit de tuer votre processus, vous pouvez parfaitement faire un " Ctrl+ C" en utilisant kill. N'envoyez pas de brutal SIGKILL. Au lieu de cela, vous pouvez utiliser:

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

Ce qui enverra un joli SIGINT(2) ou SIGTERM(15) à votre processus. Vous pouvez également vouloir imprimer la valeur PID après avoir démarré le processus:

...
nohup $cmd &
echo $!

... ou encore mieux, faites attendre le script pour un SIGINT, et renvoyez-le au processus d'arrière-plan (cela gardera votre script au premier plan) :

#!/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

Si un SIGINTne suffit pas, utilisez simplement un à la SIGTERMplace (15):

trap "kill -15 $bg_pid" 2 15

De cette façon, lorsque votre script reçoit un SIGINT( Ctrl+ C, kill -2) ou un SIGTERMcertain temps waitpour le processus d'arrière-plan, il ne fait que lui transmettre les signaux. Si ces signaux tuent l' sfkinstance, alors l' waitappel reviendra, mettant ainsi fin à votre script :)

John WH Smith
la source
1
+1 Très informatif. Étant donné que le script s'exécute dans un sous-shell, existe-t-il une possibilité d'accéder du script à la table des tâches du shell parent du script? C'est la liste des travaux émis jobsdans le terminal après la fin du script (au lieu de ps).
antonio
1
Les travaux sont associés à votre shell actuel, ils ne sont pas transmis d'un shell à l'autre. Lorsque votre sous-shell meurt, ses tâches ne sont pas récupérées. En imprimant le PID de votre processus d'arrière-plan, vous vous assurez d'obtenir facilement des informations à ce sujet même après la fin du sous-shell ( pid -p).
John WH Smith
belle explication, cependant si votre script contient plus de commandes, elles ne sont jamais exécutées (à cause de wait). Si vous supprimez l'attente, la gestion du signal est rompue: /
chefarov