Comment placer un processus déjà en cours sous nohup?


940

J'ai un processus qui fonctionne déjà depuis longtemps et je ne veux pas y mettre fin.

Comment le placer sous nohup (c'est-à-dire comment le faire continuer à fonctionner même si je ferme le terminal?)


29
Pour toute personne confrontée au même problème: rappelez-vous que même si vous tapez yourExecutable &et que les sorties continuent à apparaître sur l'écran et Ctrl+Cne semblent rien arrêter, tapez simplement aveuglément disown;et appuyez Entermême si l'écran défile avec les sorties et que vous ne pouvez pas voir ce que vous tapez. Le processus sera désavoué et vous pourrez fermer le terminal sans que le processus ne meure.
Nav

Réponses:


1367

Utilisation du Job Control de bash pour envoyer le processus en arrière-plan:

  1. Ctrl+ Zpour arrêter (mettre en pause) le programme et revenir au shell.
  2. bg pour l'exécuter en arrière-plan.
  3. disown -h [job-spec]où [job-spec] est le numéro de la tâche (comme %1pour la première tâche en cours d'exécution; recherchez votre numéro avec la jobscommande) afin que la tâche ne soit pas supprimée à la fermeture du terminal.

38
Comme la question était de savoir comment "le mettre sous nohup", c'est disown -hpeut-être la réponse la plus exacte: "faire en sorte que désavoué se comporte plus comme nohup (c'est-à-dire que les travaux resteront dans l'arbre de processus de votre shell actuel jusqu'à ce que vous quittiez votre shell). Cela vous permet de voir tous les travaux que cet obus a commencé. " (depuis [ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/… )
-Philip Gehrcke

8
Comment récupérer le travail plus tard? Je peux le voir fonctionner en utilisant ps -e.
Paulo Casaretto

26
Vous ne pouvez pas voir la sortie d'un travail après un disown, disown fait d'un processus un démon, ce qui signifie que les entrées / sorties standard sont redirigées vers / dev / null. Donc, si vous envisagez de renoncer à un travail, il vaut mieux le démarrer en vous connectant à un fichier, par exemplemy_job_command | tee my_job.log
rustyx

8
est-il possible de faire quelque chose comme 'my_job_command | tee my_job.log ' après l' exécution de la commande?
2012 à 12h53

23
disowndissocie tous les tuyaux du processus. Pour rattacher des tuyaux, utilisez gdbcomme décrit dans ce fil . Plus précisément, ce poste .
mbrownnyc

185

Supposons que pour une raison quelconque Ctrl+ Zne fonctionne pas non plus, allez sur un autre terminal, trouvez l'identifiant du processus (en utilisant ps) et exécutez:

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPsuspendra le processus et SIGCONTreprendra le processus en arrière-plan. Alors maintenant, la fermeture de vos deux terminaux n'arrêtera pas votre processus.


10
Oui, c'est un problème de système d'exploitation, kill ne fonctionne pas avec Cygwin sous Windows.
Pungs

6
Très utile également si le travail est démarré à partir d'une autre session ssh.
Amir Ali Akbari, du

5
N'oubliez pas de faire le disown %1dans le premier terminal avant de le fermer.
Fred

1
C'est utile puisque j'ai démarré une interface graphique avec une console (dans mon cas je suis parti de konsole kwinaprès un crash sans penser aux conséquences). Donc, si j'avais arrêté kwin, tout aurait gelé et je n'avais aucune possibilité de courir bg!
Michele

@fred Je n'ai pas fait ça et ça a semblé continuer à fonctionner. Possible ou ai-je atteint le mauvais PID?
Personne le

91

La commande pour séparer un travail en cours d'exécution du shell (= ne le fait pas) est disownune commande shell de base.

Depuis bash-manpage (man bash):

renoncer [-ar] [-h] [jobspec ...]

Sans option, chaque spécification de tâche est supprimée de la table des tâches actives. Si l'option -h est donnée, chaque spécification de travail n'est pas supprimée de la table, mais est marquée de sorte que SIGHUP ne soit pas envoyé au travail si le shell reçoit un SIGHUP. Si aucune spécification de tâche n'est présente et que ni l'option -a ni l'option -r n'est fournie, la tâche actuelle est utilisée. Si aucune spécification de tâche n'est fournie, l'option -a signifie supprimer ou marquer toutes les tâches; l'option -r sans argument jobspec limite l'opération aux travaux en cours d'exécution. La valeur de retour est 0, sauf si une spécification de travail ne spécifie pas de travail valide.

Cela signifie qu'un simple

disown -a

supprimera tous les travaux de la table des travaux et les rendra nohup


9
disown -asupprime tous les travaux. Un simple disownsupprime uniquement le travail en cours. Comme le dit la page de manuel de la réponse.
Rune Schjellerup Philosof du

73

Ce sont de bonnes réponses ci-dessus, je voulais juste ajouter une clarification:

Vous ne pouvez pas disownun pid ou un processus, vous disownun travail, et c'est une distinction importante.

Un travail est quelque chose qui est une notion d'un processus qui est attaché à un shell, donc vous devez jeter le travail en arrière-plan (pas le suspendre), puis le renier.

Problème:

%  jobs
[1]  running java 
[2]  suspended vi
%  disown %1

Voir http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/ pour une discussion plus détaillée sur Unix Job Control.


48

Malheureusement, disownest spécifique à bash et n'est pas disponible dans tous les shells.

Certaines versions d'Unix (par exemple AIX et Solaris) ont une option sur la nohupcommande elle-même qui peut être appliquée à un processus en cours d'exécution:

nohup -p pid

Voir http://en.wikipedia.org/wiki/Nohup


Uniquement pour AIXet Solaris. "Les versions AIX et Solaris de nohup ont une option -p qui modifie un processus en cours pour ignorer les futurs signaux SIGHUP. Contrairement à la fonction de désabonnement de bash décrite ci-dessus, nohup -p accepte les ID de processus.". Source
AlikElzin-kilaka

27

La réponse de Node est vraiment excellente, mais elle a laissé ouverte la question de savoir comment obtenir stdout et stderr redirigés. J'ai trouvé une solution sur Unix et Linux , mais elle n'est pas non plus complète. Je voudrais fusionner ces deux solutions. C'est ici:

Pour mon test, j'ai fait un petit script bash appelé loop.sh, qui imprime le pid de lui-même avec une minute de sommeil dans une boucle infinie.

$./loop.sh

Maintenant, obtenez le PID de ce processus d'une manière ou d'une autre. ps -C loop.shEst généralement assez bon, mais il est imprimé dans mon cas.

Maintenant, nous pouvons passer à un autre terminal (ou appuyez sur ^ Z et dans le même terminal). Maintenant gdbdevrait être attaché à ce processus.

$ gdb -p <PID>

Cela arrête le script (s'il est en cours d'exécution). Son état peut être vérifié par ps -f <PID>, où le STATchamp est 'T +' (ou en cas de ^ Z 'T'), ce qui signifie (man ps (1))

    T Stopped, either by a job control signal or because it is being traced
    + is in the foreground process group

(gdb) call close(1)
$1 = 0

Close (1) renvoie zéro en cas de succès.

(gdb) call open("loop.out", 01102, 0600)
$6 = 1

Open (1) renvoie le nouveau descripteur de fichier en cas de succès.

Cette ouverture est égale à open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR). Au lieu de O_RDWR O_WRONLYpourrait être appliqué, mais /usr/sbin/lsofdit «u» pour tous les gestionnaires de fichiers std * ( FDcolonne), ce qui est O_RDWR.

J'ai vérifié les valeurs dans le fichier d'en-tête /usr/include/bits/fcntl.h.

Le fichier de sortie pourrait être ouvert avec O_APPEND, comme ce nohupserait le cas, mais cela n'est pas suggéré par man open(2), en raison de problèmes NFS possibles.

Si nous obtenons -1 comme valeur de retour, call perror("")imprime alors le message d'erreur. Si nous avons besoin de l'errno, utilisez la commande p errnogdb.

Nous pouvons maintenant vérifier le fichier nouvellement redirigé. /usr/sbin/lsof -p <PID>impressions:

loop.sh <PID> truey    1u   REG   0,26        0 15008411 /home/truey/loop.out

Si nous voulons, nous pouvons rediriger stderr vers un autre fichier, si nous voulons utiliser call close(2)et à call open(...)nouveau en utilisant un nom de fichier différent.

Maintenant, la pièce jointe bashdoit être libérée et nous pouvons quitter gdb:

(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q

Si le script a été arrêté par gdbun autre terminal, il continue de s'exécuter. Nous pouvons revenir au terminal de loop.sh. Maintenant, il n'écrit plus rien à l'écran, mais s'exécute et écrit dans le fichier. Nous devons le mettre en arrière-plan. Alors appuyez sur ^Z.

^Z
[1]+  Stopped                 ./loop.sh

(Maintenant, nous sommes dans le même état que si on ^Zavait appuyé au début.)

Nous pouvons maintenant vérifier l'état de la tâche:

$ ps -f 24522
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh
$ jobs
[1]+  Stopped                 ./loop.sh

Le processus doit donc être exécuté en arrière-plan et détaché du terminal. Le nombre dans la jobssortie de la commande entre crochets identifie le travail à l'intérieur bash. Nous pouvons utiliser les bashcommandes intégrées suivantes en appliquant un signe «%» avant le numéro de travail:

$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh

Et maintenant, nous pouvons quitter le bash appelant. Le processus continue de s'exécuter en arrière-plan. Si nous quittons son PPID, il devient 1 (processus init (1)) et le terminal de commande devient inconnu.

$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID>     1  0 11:16 ?        S      0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey    0u   CHR 136,36                38 /dev/pts/36 (deleted)
loop.sh <PID> truey    1u   REG   0,26     1127 15008411 /home/truey/loop.out
loop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

COMMENTAIRE

Le truc gdb peut être automatisé en créant un fichier (par exemple loop.gdb) contenant les commandes et exécuter gdb -q -x loop.gdb -p <PID>. Mon loop.gdb ressemble à ceci:

call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit

Ou on peut utiliser la doublure suivante à la place:

gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>

J'espère que c'est une description assez complète de la solution.


Très instructif en effet, et susceptible de bien fonctionner dans des cas simples. Mais attention, les cas plus complexes peuvent échouer lamentablement. J'en ai eu un aujourd'hui: mon processus a engendré un autre processus qui a fait la sortie (vraisemblablement vers stderr), mais a stdout connecté pour communiquer avec son maître. La redirection des FD maîtres n'a pas eu d'effet car l'enfant avait hérité de stderr, et la fermeture de la sortie enfant a échoué le maître qui attendait à l'autre extrémité du tuyau. X- | Bettern connaît bien vos processus avant d'essayer.
cmaster - réintègre monica le

@cmaster Vous pouvez vérifier si une poignée est redirigé en utilisant lsof(le nom du descripteur de fichier est pipe, pas comme /dev/pts/1) ou ls -l /proc/<PID>/fd/<fd>(cela montre le lien symbolique de la poignée). De même, les sous-processus peuvent toujours ne pas avoir redirigé les sorties, qui doivent être redirigées vers un fichier.
TrueY

7

Pour envoyer le processus en cours à nohup ( http://en.wikipedia.org/wiki/Nohup )

nohup -p pid , ça n'a pas marché pour moi

Ensuite, j'ai essayé les commandes suivantes et cela a très bien fonctionné

  1. Exécutez SOMECOMMAND, par exemple /usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+ Zpour arrêter (mettre en pause) le programme et revenir au shell.

  3. bg pour l'exécuter en arrière-plan.

  4. disown -h afin que le processus ne soit pas interrompu à la fermeture du terminal.

  5. Tapez exitpour sortir du shell car maintenant vous êtes prêt à partir car l'opération s'exécutera en arrière-plan dans son propre processus, donc elle n'est pas liée à un shell.

Ce processus est équivalent à l'exécution nohup SOMECOMMAND.


3

Sur mon système AIX, j'ai essayé

nohup -p  processid>

Cela a bien fonctionné. Il a continué d'exécuter mon processus même après la fermeture des fenêtres du terminal. Nous avons ksh comme shell par défaut, donc les commandes bget disownne fonctionnaient pas.


2
  1. ctrl+ z - cela mettra le travail en pause (ne va pas annuler!)
  2. bg - cela mettra le travail en arrière-plan et reviendra dans le processus en cours
  3. disown -a - cela coupera toute la pièce jointe avec le travail (vous pouvez donc fermer le terminal et il fonctionnera toujours)

Ces étapes simples vous permettront de fermer le terminal tout en maintenant le processus en cours.

Il ne sera pas mis nohup(selon ma compréhension de votre question, vous n'en avez pas besoin ici).


Je pense que le comportement pour le reniement -a est de couper l'attachement avec tous les travaux. Cependant, il ne ferme pas les pipelines stdin / stdout, ce qui signifie que le processus essaiera toujours d'écrire (/ lire) depuis le terminal
Kelthar

-2

Cela a fonctionné pour moi sur Ubuntu linux en tcshell.

  1. CtrlZ pour le mettre en pause

  2. bg courir en arrière-plan

  3. jobs pour obtenir son numéro de travail

  4. nohup %n où n est le numéro de tâche


2
Non, cela ne fonctionne pas:nohup: failed to run command '%1': No such file or directory
Dunatotatos
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.