web-dev-qa-db-fra.com

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

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 (de plus, passer un nom de fichier ne semble pas fonctionner).

297
AnC

Tout d'abord; une fois que vous avez démarré un processus, vous pouvez l’arrière-plan en l’arrêtant d’abord (touche Ctrl-Z) puis en tapant bgpour le laisser reprendre en arrière-plan. C'est maintenant un "job", et son stdoutname __/stderrname __/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 avec tel que son stdout/stderr puisse être envoyé à un fichier à la place et que la fermeture du script parent ne détecte pas l'enfant. Cependant, vous devez avoir eu la clairvoyance de l'avoir utilisé avant de démarrer l'application. En raison du fonctionnement de Nohupname__, vous ne pouvez pas simplement l'appliquer à un processus en cours d'exécution .

disownest une commande intégrée de bash qui supprime un travail Shell de la liste des travaux du shell. Cela signifie essentiellement que vous ne pouvez plus utiliser fgname__, bgname__, mais plus important encore, lorsque vous fermez votre shell, il ne se bloque plus ni n'envoie un SIGHUPname__. Contrairement à Nohupname__, disownest utilisé after le processus a été lancé et mis en arrière-plan.

Ce que vous ne pouvez pas , 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 générer une sortie vers votre terminal. Votre Shell n'a aucune relation 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 pas 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 disposez de nombreuses options de scripts, "Nohup" étant probablement le premier à venir à l'esprit. Mais pour les processus interactifs, vous démarrez, mais vous avez oublié de taire (firefox < /dev/null &>/dev/null &), vous ne pouvez pas faire grand-chose, vraiment.

Je vous recommande d’obtenir GNU screenname__. Avec screen, vous pouvez simplement fermer votre Shell en cours d’exécution lorsque la sortie du processus devient un problème et en ouvrir un nouveau (^Ac).


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

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

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

Ce n'est probablement pas ce que vous voulez car -e ne prend que n argument. Utilisez $1 pour 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 -e ne prend qu'un seul 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 " "$@")"
335
lhunath
Nohup cmd &

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

197
dsm

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

Une autre approche que vous pouvez essayer est at now. Si vous n'êtes pas superutilisateur, votre permission d'utiliser at peut être restreinte.

59
Randy Proctor

En lisant ces réponses, j'ai eu l’impression initiale que l’émission de Nohup <command> & serait suffisante. En exécutant zsh dans gnome-terminal, j’ai constaté que Nohup <command> & n’empêchait pas mon shell de tuer les processus enfants à la sortie. Bien que Nohup soit 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 signal SIGHUP.

Dans mon cas, Nohup aurait 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 gestionnaire SIGHUP. 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 veillant à ce que le processus soit supprimé de la table des tâches du shell. Si Nohup est remplacé par un shell intégré, comme cela peut parfois arriver, cela peut suffire, toutefois, si ce n'est pas le cas ...


disown est un shell intégré dans bash, zsh et 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 ressemble le gestionnaire SIGHUP, 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 pstree si 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 prend pas en charge disown? Je recommanderais fortement de passer à un système qui le fait, mais en l'absence de cette option, vous avez quelques choix.

  1. screen et tmux peuvent 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 setopt Nohup de zsh. Cela peut être utilisé pour spécifier que SIGHUP ne doit pas être envoyé aux travaux de 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 ~/.zshrc si vous le souhaitez toujours.
  3. Trouvez un moyen de modifier le tableau des tâches. Je ne pouvais pas trouver un moyen de faire cela dans tcsh ou csh, ce qui est quelque peu dérangeant.
  4. Ecrivez un petit programme C pour bifurquer et exec(). C'est une très mauvaise solution, mais la source ne devrait consister qu'en une douzaine 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.
38
Stephen Rosen
  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. De plus, disown a un indicateur Nohup de -h, peut rejeter tous les processus dotés de -a et peut renoncer à 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!

26
Mr. Minty Fresh

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 bloquera toujours le processus ssh.

9
Nathan Fellman

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

9
dunkyp

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.

7
ManuelSchneid3r

Pour dissocier la commande d'exécution tty Shell via un 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.

7
jitendra

Arrière-plan et mise au premier plan d'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
6
djangofan

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.

4
Ben

Essayez daemon - devrait être disponible auprès de votre gestionnaire de paquets convivial et doit prendre en charge de manière exhaustive tout moyen de se dissocier du terminal.

2
ShiDoiSi

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
2
B. Branchard

Dans mon .bashrc, j’ai ces fonctions précisément pour cela:

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

function dos() {
    # run_disowned and silenced

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

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

La fonction est écrite pour fonctionner avec bash et zsh.

1
mic_e

J'ai trouvé sur Mac OS X que je devais utiliser à la fois Nohup ET désavoué pour que le processus enfant ne soit pas anéanti par le terminal.

0
aaron

J'utilise le script suivant pour le faire. Il arrête le processus d'impression sur le terminal, se détache avec Nohup et se termine avec le statut de retour si la commande se termine dans la 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
>>>
0
jozxyqk