Comment détacher un processus de Terminal, entièrement?

304

J'utilise Tilda (terminal à menu déroulant) sur Ubuntu en tant que "centre de commande" - à peu près comme d'autres pourraient utiliser GNOME Do, Quicksilver ou Launchy.

Cependant, je ne parviens pas à détacher complètement un processus (par exemple, Firefox) du terminal depuis lequel il a été lancé - c'est-à-dire à empêcher qu'un tel processus (non) enfant

  • se termine lors de la fermeture du terminal d'origine
  • "pollue" le terminal d'origine via STDOUT / STDERR

Par exemple, afin de démarrer Vim dans une fenêtre de terminal "correcte", j'ai essayé un script simple comme celui-ci:

exec gnome-terminal -e "vim $@" &> /dev/null &

Cependant, cela cause toujours de la pollution (également, passer un nom de fichier ne semble pas fonctionner).

slhck
la source
1
C'est aussi une bonne question. Je pense qu'il est juste de considérer Bash comme un langage de programmation - même si en effet le champ de cette question est probablement plus du côté des administrateurs système ...
Ceci est une copie de cette question stackoverflow.com/questions/285015/…
Dana the Sane
Votre cas d'utilisation ne décrit pas un détachement complet en soi.
Jiggunjer

Réponses:

344

Tout d'abord; une fois que vous avez démarré un processus, vous pouvez l’arrière-plan en l’arrêtant d’abord (en appuyant sur Ctrl- Z), puis en le tapant bgpour le laisser reprendre en arrière-plan. C'est maintenant un "job", et ses stdout/ stderr/ stdinsont toujours connectés à votre terminal.

Vous pouvez démarrer un processus en arrière-plan immédiatement en ajoutant un "&" à la fin de celui-ci:

firefox &

Pour l'exécuter en arrière-plan silencieux, utilisez ceci:

firefox </dev/null &>/dev/null &

Quelques informations supplémentaires:

nohupest un programme que vous pouvez utiliser pour exécuter votre application de telle sorte que son stdout / stderr puisse être envoyé à un fichier et que la fermeture du script parent ne SIGHUPENT pas l'enfant. Cependant, vous devez avoir eu la clairvoyance de l'avoir utilisé avant de démarrer l'application. En raison de son nohupfonctionnement, vous ne pouvez pas l' appliquer à un processus en cours d'exécution .

disownest une bash intégrée qui supprime un travail shell de la liste des travaux du shell. Ce que cela signifie essentiellement que vous ne pouvez pas utiliser fg, bglà - dessus plus, mais plus important encore , lorsque vous fermez votre shell il ne se bloque pas ou envoyer un SIGHUPà cet enfant plus. Contrairement à nohup, disownest utilisé après le lancement et la mise en arrière du processus.

Ce que vous ne pouvez pas faire, c'est modifier le stdout / stderr / stdin d'un processus après l'avoir lancé. Du moins pas de la coquille. Si vous lancez votre processus et que vous lui indiquez que sa sortie standard est votre terminal (ce que vous faites par défaut), alors ce processus est configuré pour être exporté vers votre terminal. Votre shell n'a rien à voir avec la configuration FD des processus, c'est simplement quelque chose que gère le processus lui-même. Le processus lui-même peut décider de fermer ou non son stdout / stderr / stdin, mais vous ne pouvez pas utiliser votre shell pour le forcer à le faire.

Pour gérer la sortie d'un processus en arrière-plan, vous avez beaucoup d'options dans les scripts, "nohup" étant probablement le premier à venir à l'esprit. Mais pour les processus interactifs, vous commencez mais vous avez oublié de vous taire ( firefox < /dev/null &>/dev/null &), vous ne pouvez vraiment pas en faire beaucoup.

Je vous recommande d'utiliser GNU screen. Avec screen, vous pouvez simplement fermer votre shell en cours d’exécution lorsque la sortie du processus vous gêne et en ouvrir un nouveau ( ^Ac).


Oh, et d'ailleurs, n'utilisez pas " $@" là où vous l'utilisez.

$@signifie, $1, $2, $3..., qui tournerait votre commande en:

gnome-terminal -e "vim $1" "$2" "$3" ...

C'est probablement pas ce que vous voulez parce que -e ne prend un argument. Utilisez $1pour montrer que votre script ne peut gérer qu'un seul argument.

Il est vraiment difficile de faire fonctionner plusieurs arguments correctement dans le scénario que vous avez donné (avec le gnome-terminal -e) car -eil ne prend qu'un argument, qui est une chaîne de commande shell. Vous devrez encoder vos arguments en un seul. La meilleure et la plus robuste, mais assez lourde, ressemble à ceci:

gnome-terminal -e "vim $(printf "%q " "$@")"
lhunath
la source
Merci beaucoup pour cela! Malheureusement, je ne peux accepter qu'une seule réponse. Je me suis retrouvé avec "nohup $ @ &> / dev / null &" et "alias wvim = 'launch.sh gnome-terminal -x vim" "
20
Quelle réponse fantastiquement détaillée et informative. +1
Teekin
1
@ Hi-Angel lorsque vous fermez un shell bash interactif, bash HUP tous les travaux actifs. Lorsque vous travaillez sur un processus, c’est toujours un travail, qu’il s’agisse d’un travail de fond. Pour le supprimer en tant que travail, utilisez disown, le processus continuera à vivre une fois que vous aurez fermé le shell, car bash ne le traitera plus.
Lhunath
3
Est-ce que ne pas utiliser au $*lieu de $@résoudre le problème des différentes chaînes déjà?
samedi
2
Ce que vous ne pouvez pas faire, c'est modifier le stdout / stderr / stdin d'un processus après l'avoir lancé. - pas tout à fait vrai. Utilisez reptyrpour cela.
Stefan Seidel
198
nohup cmd &

nohup détache complètement le processus (le démonise)

dsm
la source
5
Bien que succincte ait de la valeur, la complétude l'est plus. Bien que nohup soit un coreutil de GNU, une réponse uniquement en bash (ou une note indiquant qu’il n’en existe pas) conviendrait ici. Bonne réponse néanmoins.
Expiation limitée
23
nohupignore simplement le SIGHUPsignal. Il exécute le processus normalement. Pas de démonisation.
Nemo
1
@nemo Ce qui signifie que le processus n'est pas détaché, mais le deviendrait (et deviendrait un enfant de init) si la coquille quittait ... non?
Noldorin
@ Noldorin Oui. Ignorer SIGHUP, qui est envoyé à la fin du shell, laissera le processus enfant s'exécuter et sera déplacé vers init.
Nemo
@nemo nohup supprime également les entrées / sorties standard. Suivi avec désavoué pour se détacher complètement.
jiggunjer
60

Si vous utilisez bash, essayez ; voir bash (1) .disown [jobspec]

Une autre approche que vous pouvez essayer est at now. Si vous n'êtes pas superutilisateur, votre autorisation d'utilisation atpeut être restreinte.

Randy Proctor
la source
"désavoué" ne semble pas être une commande interne bash (non disponible sur ma machine et j'utilise bash). "nohup", comme le suggérait Ben, pourrait être un moyen bien meilleur (et standard) de le faire.
1
jamais pensé à utiliser "à", merci pour l'idée!
Cadrian
1
atdéléguer l'exécution à quelqu'un d'autre, j'aime bien! +1
Ninsuo
1
En tant que référence, cela fonctionne zshégalement.
Coderer
1
De plus, disownil ne semble pas que l'effet souhaité soit atteint gnome-terminal, disowncar les processus sont toujours supprimés à la sortie du terminal. J'aimerais savoir pourquoi / comment.
Kyle Strand
38

En lisant ces réponses, j’avais l’impression initiale que l’émission nohup <command> &serait suffisante. En exécutant zsh dans gnome-terminal, j'ai découvert que cela nohup <command> &n'empêchait pas mon shell de tuer les processus enfants à la sortie. Bien que cela nohupsoit utile, en particulier avec les shells non interactifs, il ne garantit ce comportement que si le processus enfant ne réinitialise pas son gestionnaire pour le SIGHUPsignal.

Dans mon cas, nohupj'aurais dû empêcher les signaux de raccrochage d'atteindre l'application, mais l'application enfant (VMWare Player dans ce cas) était en train de réinitialiser son SIGHUPgestionnaire. Par conséquent, lorsque l'émulateur de terminal se ferme, il pourrait toujours tuer vos sous-processus. À ma connaissance, cela ne peut être résolu qu'en s'assurant que le processus est supprimé de la table des tâches du shell. Si nohupest écrasé avec un shell intégré, comme c'est parfois le cas, cela peut être suffisant, cependant, dans le cas où ce n'est pas le cas ...


disownest une commande interne à bash, zshet ksh93,

<command> &
disown

ou

<command> &; disown

si vous préférez les one-liners. Cela a généralement pour effet souhaitable de supprimer le sous-processus de la table des tâches. Cela vous permet de quitter l'émulateur de terminal sans signaler accidentellement le processus enfant. Peu importe ce à quoi SIGHUPressemble le gestionnaire, cela ne devrait pas tuer votre processus enfant.

Après le désaveu, le processus est toujours un enfant de votre émulateur de terminal (jouez avec pstreesi vous voulez regarder cela en action), mais après la sortie de l'émulateur de terminal, vous devriez le voir attaché au processus init. En d'autres termes, tout est comme il se doit, et comme vous le souhaitez vraisemblablement.

Que faire si votre shell ne supporte pas disown? Je recommanderais fortement de passer à un système qui le fait, mais en l'absence de cette option, vous avez quelques choix.

  1. screenet tmuxpeuvent résoudre ce problème, mais ce sont des solutions beaucoup plus lourdes, et je n'aime pas avoir à les exécuter pour une tâche aussi simple. Ils sont bien plus adaptés aux situations dans lesquelles vous souhaitez gérer un terminal, généralement sur une machine distante.
  2. Pour de nombreux utilisateurs, il peut être souhaitable de voir si votre shell prend en charge une fonctionnalité telle que celle de zsh setopt nohup. Cela peut être utilisé pour spécifier que SIGHUPne doit pas être envoyé aux travaux dans la table des travaux lorsque le shell se ferme. Vous pouvez l'appliquer juste avant de quitter le shell ou l'ajouter à la configuration du shell, comme ~/.zshrcsi vous le vouliez toujours.
  3. Trouvez un moyen de modifier le tableau des tâches. Je ne pouvais pas trouver un moyen de faire cela en tcshou cshce qui est un peu dérangeant.
  4. Ecrivez un petit programme en C pour bifurquer et exec(). C'est une très mauvaise solution, mais la source ne devrait comporter que quelques dizaines de lignes. Vous pouvez ensuite passer des commandes sous forme d'arguments de ligne de commande au programme C et éviter ainsi une entrée spécifique au processus dans le tableau des travaux.
Stephen Rosen
la source
29
  1. nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

J'utilise le numéro 2 depuis très longtemps, mais le numéro 3 fonctionne aussi bien. En outre, disowna un nohupdrapeau de -h, peut désavouer tous les processus avec -aet peut désavouer tous les processus en cours d'exécution avec -ar.

Le silence est accompli par $COMMAND &>/dev/null.

J'espère que cela t'aides!

M. Menthe Frais
la source
Court et doux; merci pour ce résumé très utile!
Sheljohn
Je ne peux pas croire que je reçois toujours des notifications pour ce poste ...
M. Minty Fresh Le
9

Je pense que l'écran pourrait résoudre votre problème


la source
9

dans tcsh (et peut-être aussi dans d'autres shells), vous pouvez utiliser des parenthèses pour détacher le processus.

Comparez ceci:

> jobs # shows nothing
> firefox &
> jobs
[1]  + Running                       firefox

Pour ça:

> jobs # shows nothing
> (firefox &)
> jobs # still shows nothing
>

Ceci supprime Firefox de la liste des tâches, mais reste lié au terminal. Si vous vous êtes connecté à ce nœud via 'ssh', le fait d'essayer de vous déconnecter suspendra le processus ssh.

Nathan Fellman
la source
9

La réponse la plus simple et la plus correcte pour bash:

command & disown

Vous ne devez pas détacher le processus du terminal, mais du shell.

ManuelSchneid3r
la source
7

Pour dissocier la commande d'exécution du shell tty via le sous-shell, par exemple

(commander)&

Lorsque la sortie utilisée terminal fermé, mais le processus est toujours en vie.

vérifier -

(sleep 100) & exit

Ouvrir un autre terminal

ps aux | grep sleep

Le processus est toujours en vie.

Jitendra
la source
C'est exactement ce dont j'avais besoin. J'essayais d'ajouter un raccourci de console pour un texte sublime et cela fonctionne parfaitement, voici ce que j'ai fini avec: ("/ opt / Sublime Text 2 / sublime_text" $ @) &
Ron E
5

Mettre en arrière-plan et mettre en avant un travail est probablement l'une des toutes premières choses que tout administrateur système Unix doit savoir.

Voici comment cela se fait avec bash:

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
djangofan
la source
4

Vous pouvez exécuter votre commande en utilisant la commande nohup, cela détache votre processus et redirige les sorties vers un fichier donné ... mais je ne suis pas sûr que ce soit exactement ce dont vous avez besoin.

Ben
la source
Je pourrais jurer que j'avais essayé nohup avant d'utiliser exec - mais apparemment pas correctement, car cela fonctionne comme ceci: nohup gnome-terminal -e "vim $ @" &> / dev / null &
2

Essayez le démon - devrait être disponible à partir de votre gestionnaire de paquets convivial et veille de manière exhaustive à chaque moyen de se dissocier du terminal.

ShiDoiSi
la source
2

Ajoutez simplement ceci dans votre bashrc / zshrc:

detach() {
  "$@" 1>/dev/null 2>/dev/null &; disown
}

Ensuite, vous pouvez exécuter des commandes désapprouvées comme ceci:

detach gedit ~/.zshrc
B. Branchard
la source
1

Dans mon .bashrc, j'ai ces fonctions précisément dans ce but:

function run_disowned() {
    "$@" & disown
}

function dos() {
    # run_disowned and silenced

    run_disowned "$@" 1>/dev/null 2>/dev/null
}

Préfixez une commande avec dospour l'exécuter détachée du terminal.

La fonction est écrite pour fonctionner avec bashet zsh.

mic_e
la source
1
Je suis un peu confus quant à la raison pour laquelle cette réponse utilise une fonction enveloppée dans une autre, lorsque son suffisante pour utiliser une seule fonction avec le corps comme ceci: ( "$@" & disown) &> /dev/null. Il est également logique pas grand chose à utiliser 1>et 2>, parce que vous utilisez disown, ce qui signifie utilisez bash, et bash , vous pouvez le faire facilement &>réacheminer à la fois stdout et stderr
Sergiy Kolodyazhnyy
Je l’ai sous forme de deux fonctions parce que (1) je pense qu’il est plus facile de lire de cette façon, et (2) j’ai besoin de la run_disownedfonctionnalité à d’autres endroits de mes fichiers de points. Vous avez raison à propos de la &>chose, bien sûr.
mic_e
0

J'ai trouvé sur Mac OS X que je devais utiliser à la fois nohup AND désavoué pour m'assurer que le processus enfant ne soit pas démantelé avec le terminal.

Aaron
la source
0

J'utilise le script suivant pour le faire. Il arrête le processus d'impression sur le terminal, se détache avec nohup, et quitte avec le statut de retour si la commande se termine dans les TIMEOUT.

#!/bin/bash

TIMEOUT=0.1

CMD=( "$@" )
#Could have some shortcuts here, e.g. replace "somefile.c" with "gedit somefile.c"

#use nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send nohup's output to /dev/null, supressing nohup.out
#run nohup in the background so this script doesn't block
#print the command for debugging and to see bash variable expansion
printf "%q " "${CMD[@]}"
echo
nohup "${CMD[@]}" >/dev/null 2>&1 &
NOHUP_PID=$!

#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally

#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $NOHUP_PID
NOHUP_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[ $NOHUP_STATUS != 0 ] && echo "Error: $CMD"
#return the exit status of nohup, whatever it was
exit $NOHUP_STATUS

Exemple d'utilisation:

>>> run false
false
Error: false
>>> echo $?
1
>>> run true
true
>>> run sleep 10
sleep 10
>>>
jozxyqk
la source
0

sudo apt install ucommon-utils

pdetach command

Voilà :)

d4rk4ng31
la source
-1

Beaucoup de réponses ont suggéré d'utiliser nohup . Je suggérerais plutôt d'utiliser pm2 . L'utilisation de pm2 over nohup présente de nombreux avantages, tels que la maintenance de l'application, la maintenance des fichiers journaux de l'application et bien d'autres fonctionnalités. Pour plus de détails, consultez ceci .

Pour installer pm2, vous devez télécharger npm . Pour un système basé sur Debian

sudo apt-get install npm

et pour Redhat

sudo yum install npm

Ou vous pouvez suivre ces instructions . Après avoir installé npm, utilisez-le pour installer pm2

npm install pm2@latest -g

Une fois que vous avez terminé, vous pouvez commencer votre application en

$ pm2 start app.js              # Start, Daemonize and auto-restart application (Node)
$ pm2 start app.py              # Start, Daemonize and auto-restart application (Python)

Pour la surveillance du processus, utilisez les commandes suivantes:

$ pm2 list                      # List all processes started with PM2
$ pm2 monit                     # Display memory and cpu usage of each app
$ pm2 show [app-name]           # Show all informations about application

Gérez les processus à l'aide du nom de l'application ou de l'ID de processus ou gérez tous les processus ensemble:

$ pm2 stop     <app_name|id|'all'|json_conf>
$ pm2 restart  <app_name|id|'all'|json_conf>
$ pm2 delete   <app_name|id|'all'|json_conf>

Les fichiers de log peuvent être trouvés dans

$HOME/.pm2/logs #contain all applications logs
haccks
la source
1
Utiliser une application NodeJS (par opposition à une commande petite et robuste comme celle de nohup) pour contrôler les processus unix semble ... vraiment exagéré, et pour être honnête, plutôt étrange. J'utiliserais monit si vous avez besoin de la fonctionnalité de redémarrage.
Sergio
@Sergio c'est votre choix d'utiliser une application privée.
haccks
Plusieurs versions ont été publiées cette année (une il y a 4 jours), donc je ne vois pas comment / pourquoi vous pensez que monit est une application obsolète. @see mmonit.com/monit/changes
Sergio
Je parlais de nohup.
haccks
1
nohupest une commande POSIX standard simple, donc même remarque: elle n’est en aucun cas obsolète. @see unix.com/man-page/posix/1p/nohup
Sergio
-1

Si votre objectif est simplement de lancer une application en ligne de commande sans conserver la fenêtre du terminal, vous pouvez essayer de l'exécuter après le lancement du terminal avec alt-F2.

Matt Kelly
la source