Quelqu'un peut-il expliquer en détail ce que fait «set -m»?

16

Sur la page de manuel , il dit simplement:

-m Le contrôle des travaux est activé.

Mais qu'est-ce que cela signifie réellement?

Je suis tombé sur cette commande dans une question SO , j'ai le même problème que OP, qui est "le tissu ne peut pas démarrer tomcat". Et set -mrésolu cela. L'OP a expliqué un peu, mais je ne comprends pas très bien:

Le problème était dans les tâches en arrière-plan car elles seront tuées à la fin de la commande.

La solution est simple: ajoutez simplement "set -m;" préfixe avant la commande.

laike9m
la source

Réponses:

10

Citant la documentation bash (de 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.

Donc, tout simplement dit, avoir set -m(la valeur par défaut pour les shells interactifs) permet d'utiliser des éléments intégrés tels que fget bg, qui seraient désactivés sous set +m(la valeur par défaut pour les shells non interactifs).

Cependant, il n'est pas évident pour moi quelle est la connexion entre le contrôle des travaux et la suppression des processus d'arrière-plan à la sortie, mais je peux en confirmer qu'il y en a un: l'exécution set -m; (sleep 10 ; touch control-on) &créera le fichier si l'on quitte le shell juste après avoir tapé cette commande, mais set +m; (sleep 10 ; touch control-off) &ne le fera pas.

Je pense que la réponse réside dans le reste de la documentation pour 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.

Cela signifie que les jobs d'arrière-plan démarrés sous set +mne sont pas de véritables "processus d'arrière-plan" ("les processus d'arrière-plan sont ceux dont l'ID de groupe de processus diffère de celui du terminal"): ils partagent le même ID de groupe de processus que le shell qui les a démarrés, plutôt que d'avoir leur propre groupe de processus comme les processus d'arrière-plan appropriés. Cela explique le comportement observé lorsque le shell se ferme avant certains de ses jobs d'arrière-plan: si je comprends bien, lors de la fermeture, un signal est envoyé aux processus dans le même groupe de processus que le shell (tuant ainsi les jobs d'arrière-plan démarrés sous set +m), mais pas à ceux d'autres groupes de processus (laissant ainsi seuls les véritables processus d'arrière-plan commencés set -m).

Donc, dans votre cas, le startup.shscript démarre probablement un travail d'arrière-plan. Lorsque ce script est exécuté de manière non interactive, comme sur SSH comme dans la question à laquelle vous avez lié, le contrôle des travaux est désactivé, le travail "d'arrière-plan" partage le groupe de processus du shell distant et est donc tué dès que le shell se ferme. Inversement, en activant le contrôle des travaux dans ce shell, le travail d'arrière-plan acquiert son propre groupe de processus et n'est pas tué lorsque son shell parent se ferme.

dhag
la source
Merci pour votre réponse, mais quel est le tomcat/bin/startup.shlien avec fg/ bg?
laike9m
1
Ce n'est pas directement lié; J'essayais de répondre "Le contrôle des tâches est activé / qu'est-ce que cela signifie réellement?" d'une manière générale. Peut-être que je n'ai pas été clair, mais votre script semble démarrer un travail d'arrière-plan, ce à quoi le reste de ma réponse s'applique.
dhag
2

Je l'ai trouvé sur la liste des problèmes de github, et je pense que cela répond vraiment à votre question.

Ce n'est pas vraiment un problème SSH, c'est plutôt le comportement subtil autour des modes BASH non interactifs / interactifs et de la propagation du signal vers les groupes de processus.

Ce qui suit est basé sur /programming/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 et http: //www.itp.uzh.ch/~dpotter/howto/daemonize , avec certaines hypothèses non entièrement validées, mais des tests sur la façon dont cela fonctionne semblent confirmer.

pty / tty = false

Le shell bash lancé se connecte à stdout / stderr / stdin du processus démarré et continue de fonctionner jusqu'à ce qu'il n'y ait rien attaché aux sockets et que ses enfants soient sortis. Un bon processus de démon s'assurera qu'il n'attend pas que ses enfants se terminent, fork un processus enfant puis quitte. Dans ce mode, aucun SIGHUP ne sera envoyé au processus enfant par SSH. Je crois que cela fonctionnera correctement pour la plupart des scripts exécutant un processus qui gère lui-même la désamorçage et n'a pas besoin d'être mis en arrière-plan. Lorsque les scripts d'initialisation utilisent '&' pour mettre en arrière-plan un processus, il est probable que le principal problème sera de savoir si le processus en arrière-plan tentera jamais de lire à partir de stdin, car cela déclenchera un SIGHUP si la session est terminée.

pty / tty = true *

Si le script init met en arrière-plan le processus démarré, le shell BASH parent retournera un code de sortie à la connexion SSH, qui à son tour cherchera à quitter immédiatement car il n'attend pas la fin d'un processus enfant et n'est pas bloqué sur stdout / stderr / stdin. Cela entraînera l'envoi d'un SIGHUP au groupe de processus shell bash parent qui, puisque le contrôle des travaux est désactivé en mode non interactif dans bash, inclura les processus enfants qui viennent d'être lancés. Lorsqu'un processus démon démarre explicitement une nouvelle session de processus lors de la fourche ou dans le processus forké, il ou ses enfants ne recevront pas le SIGHUP du processus parent BASH sortant. Notez que ceci est différent des travaux suspendus qui verront un SIGTERM. Je soupçonne que les problèmes autour de cela ne fonctionnent que parfois à cause d'une légère condition de concurrence. http://www.itp.uzh.ch/~dpotter/howto/daemonize , vous verrez que dans le code la nouvelle session est créée par le processus forké qui ne peut pas être exécuté avant la sortie du parent, ce qui entraîne l'aléatoire comportement de réussite / échec mentionné ci-dessus. Une instruction sleep laissera suffisamment de temps pour que le processus forké ait créé une nouvelle session, c'est pourquoi cela fonctionne dans certains cas.

pty / tty = true et le contrôle des travaux est explicitement activé dans bash

SSH ne se connectera pas à stdout / stderr / stdin du shell bash ni à aucun processus enfant lancé, ce qui signifie qu'il se fermera dès que le shell bash parent aura commencé à exécuter les commandes demandées. Dans ce cas, avec le contrôle des travaux explicitement activé, tous les processus lancés par le shell bash avec '&' pour les mettre en arrière-plan seront immédiatement placés dans une session distincte et ne recevront pas le signal SIGHUP lorsque le processus parent de la session BASH se terminera ( Connexion SSH dans ce cas).

Ce qui est nécessaire pour réparer

Je pense que les solutions doivent simplement être explicitement mentionnées dans la documentation des opérations run / sudo comme un cas spécial lorsque vous travaillez avec des processus / services en arrière-plan. Fondamentalement, utilisez 'pty = false' ou, lorsque cela n'est pas possible, activez explicitement le contrôle des travaux comme première commande et le comportement sera correct.

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

pootow
la source