Pourquoi certaines commandes "suspendent" le terminal jusqu'à ce qu'elles soient terminées?

22

Parfois, vous exécutez un programme à partir du terminal, par exemple lxpanel . Le terminal ne vous ramènera pas à l'invite, il se bloquera. Vous pouvez appuyer sur Ctrl+ Cpour revenir à l'invite, mais cela tuera lxpanel. Cependant, appuyer sur Alt+ F2(qui fait apparaître une fenêtre pour prendre une commande) et exécuter lxpanelfonctionne correctement.

Pourquoi est-ce? Qu'est-ce qui est différent entre l'exécution d'une commande à partir du terminal et de la fenêtre «Exécuter» qui apparaît lorsque vous appuyez sur Alt+ F2?

lxpanel ici vient d'être utilisé comme exemple. J'ai vécu cela avec plusieurs programmes

sqram
la source
1
Astuce: GNU Screen ( screen) peut, entre autres, être utilisé pour «encapsuler» des processus plus longs. Vous pouvez vous en détacher, revenir au shell, puis le rattacher et voir la sortie du processus en cours. Le rattachement peut même être effectué à partir d'un autre terminal, SSH, etc. Il peut également y avoir d'autres programmes qui vous permettent de faire ce genre de choses.
poplitea

Réponses:

28

Par défaut, le terminal exécutera le programme au premier plan, donc vous ne reviendrez pas au shell tant que le programme ne sera pas terminé. Ceci est utile pour les programmes qui lisent depuis stdin et / ou écrivent vers stdout - vous ne voulez généralement pas que plusieurs d'entre eux s'exécutent en même temps. Si vous voulez qu'un programme s'exécute en arrière-plan, vous pouvez le démarrer comme ceci:

$ lxpanel &

Ou s'il est déjà en cours d'exécution, vous pouvez le suspendre avec Ctrl+ Zpuis exécuter bgpour le déplacer en arrière-plan. Quoi qu'il en soit, vous vous retrouverez avec une nouvelle invite de shell, mais le programme est toujours en cours d'exécution et sa sortie apparaîtra dans le terminal (afin qu'il puisse apparaître soudainement pendant que vous êtes en train de taper)

Certains programmes (généralement des démons) vont bifurquer un processus distinct lorsqu'ils démarrent, puis laisser le processus principal se terminer immédiatement. Cela permet au programme de continuer à fonctionner sans bloquer votre shell

Michael Mrozek
la source
Que fait donc le système lorsque vous exécutez le programme via la fenêtre "Exécuter" en appuyant sur Alt + f2? (au moins sur gnome et openbox, alt + f2 fait ça). Je demande parce que dès que vous tapez la commande, le programme démarre et la boîte disparaît. est-ce simplement en y ajoutant un &?
sqram
2
@lyrae: par défaut, le shell attend la fin du programme avant de continuer la session shell, il ne se "bloque" pas, quelle que soit la définition de "se bloquer"; alt + f2 n'attend pas le programme. La raison pour laquelle le shell attend la fin du programme est que le shell peut rediriger tout ce que l'utilisateur a tapé dans le shell vers l'entrée standard du programme et / ou afficher la sortie standard du programme. Comme alt + f2 est principalement utilisé pour démarrer un programme GUI, alt + f2 ne fournit pas la possibilité d'utiliser une entrée / sortie standard et il n'est donc pas nécessaire d'attendre.
Lie Ryan
1
@lyrae: alt + f2 ne fait rien de spécial pour démarrer le programme en arrière-plan; c'est le shell qui fait quelque chose de spécial, ajouter '&' est la fonctionnalité du shell. Lors du démarrage d'une commande sans '&', le shell redirige l'entrée standard du programme vers sa propre entrée standard et la sortie standard du programme vers sa propre sortie standard (un peu artificielle, car le shell fournit également de nombreux autres services, tels que l'interception de Ctrl -C, pour envoyer une commande de signal SIGINT au programme de premier plan). Le «&» indique au shell de ne pas faire cela et de simplement démarrer le programme (également conçu).
Lie Ryan
1
@LieRyan une partie de ce que vous dites que le shell fait est en fait géré par le pilote de terminal du noyau, et "avec &" est généralement plus "spécial" que "sans &", à part le fait que le shell appelle wait () [ou waitpid ou équivalent] qui n'est pas fait par alt-f2.
Random832
6

Lorsque vous démarrez un programme dans un terminal, le terminal se "bloque" jusqu'à ce que votre programme s'arrête. En appuyant sur Ctrl+, cvous fermez votre programme et revenez ainsi à l'invite. Vous le verrez avec toutes les applications GUI, essayez Firefox, par exemple.

Lorsque vous utilisez une autre méthode telle que Alt + F2 ou cliquez sur les menus, votre programme est démarré en arrière-plan, donc rien de bizarre ne se produit (et il n'y a pas d'invite de commande de toute façon).

Si vous souhaitez toujours lancer des applications GUI à partir du terminal, ajoutez &à la fin de votre commande, comme ceci

lxpanel &

Cela indique au terminal de fonctionner lxpanelen arrière-plan et vous donne immédiatement une autre invite.

phunehehe
la source
3

Les programmes s'exécutent via un shell exécuté au premier plan de ce shell par défaut. Cela provoque l'interruption du fonctionnement du shell et dirige stdin / stdout / sterr du terminal vers le programme. Les programmes exécutés via l'environnement de bureau sont bifurqués , ce qui les oblige à s'exécuter indépendamment du programme qui les a exécutés. Cela peut être simulé dans la plupart des shells en ajoutant a &à la commande, bien que cela connecte toujours std * au terminal (bien que la lecture de stdin sur un programme en arrière-plan présente d'autres complications).

Ignacio Vazquez-Abrams
la source
2

Les & arrière-plans bien, sauf pour les programmes qui reviennent nécessitant une interaction avec la console plus tard (par exemple, une "mise à jour apt -y &" qui finit par entrer dans l'état STOP car il veut inviter l'utilisateur une question "vraiment vraiment forcée?" Beaucoup plus tard .... quand personne ne regarde plus).

Pour boucher ce trou et informer le processus qu'un terminal ne sera jamais vraiment disponible, j'ajoute un <& - à certaines de mes commandes, les détachant complètement du terminal actif en leur disant que STDIN n'est plus possible. Assurez-vous que / bin / bash est votre shell si vous l'utilisez bien. Le script continuera d'enregistrer toutes les erreurs liées à l'absence de pseudoterminal sur lequel lancer une invite.

Par exemple:

`./runme.sh &> runme.log <&- & disown`

est ma façon ultime de me dissocier de la session terminale actuelle. STDOUT et STDERR sont tous deux connectés à runme.log, peu importe si votre console ou votre shell se termine plus tôt ou si vous vous déconnectez / su sur un compte différent (pas de déchets de terminal de runme), et merci de renier même le parent-enfant La relation PID est supprimée.

MISE À JOUR: même avec cela, j'ai eu des problèmes avec un sémaphore l'associant au nom du parent d'origine, alors maintenant je recommande à la place:

at now <<< "(cmd1; cmd2; etc.) &> logfile.log"

Bien sûr, supprimez le &> si vous souhaitez recevoir par e-mail la sortie de CRON, ou redirigez le tout vers / dev / null au lieu d'un fichier.

Marcos
la source
Une façon un peu moins compliquée d'atteindre ce que j'ai commencé à utiliser estat now <<< "(cmd1; cmd2; etc.) &> logfile.log"
Marcos