web-dev-qa-db-fra.com

Comment empêcher un processus d'arrière-plan d'être arrêté après la fermeture du client SSH sous Linux

Je travaille sur une machine Linux via SSH (PuTTY). Je dois laisser un processus en cours d'exécution pendant la nuit. Je pensais donc pouvoir le faire en démarrant le processus en arrière-plan (avec une esperluette à la fin de la commande) et en redirigeant stdout vers un fichier.

À ma grande surprise, ça ne marche pas. Dès que je ferme la fenêtre PuTTY, le processus est arrêté.

Comment puis-je empêcher que cela ne se produise?

280
GetFree

Découvrez le programme " Nohup ".

297
JesperE

Je recommanderais d'utiliser écran GN . Il vous permet de vous déconnecter du serveur pendant que tous vos processus continuent de s'exécuter. Je ne sais pas comment je vivais sans elle avant de savoir qu'elle existait.

163
gpojd

Lorsque la session est fermée, le processus reçoit le signal SIGHUP qu’il ne semble apparemment pas capter. Vous pouvez utiliser la commande Nohup lors du lancement du processus ou la commande intégrée bash disown -h après avoir lancé le processus pour éviter que cela ne se produise:

> help disown
disown: disown [-h] [-ar] [jobspec ...]
     By default, removes each JOBSPEC argument from the table of active jobs.
    If the -h option is given, the job is not removed from the table, but is
    marked so that SIGHUP is not sent to the job if the Shell receives a
    SIGHUP.  The -a option, when JOBSPEC is not supplied, means to remove all
    jobs from the job table; the -r option means to remove only running jobs.
79
Robert Gamble

démoniser? nohup? ÉCRAN? (tmux ftw, l'écran est indésirable ;-)

Faites ce que toutes les autres applications ont fait depuis le début - double fork.

# ((exec sleep 30)&)
# grep PPid /proc/`pgrep sleep`/status
PPid:   1
# jobs
# disown
bash: disown: current: no such job

Coup! Fait :-) J'ai utilisé ces innombrables fois sur tous les types d'applications et sur de nombreuses vieilles machines. Vous pouvez combiner avec des redirections et autres actions pour ouvrir un canal privé entre vous et le processus.

Créez en tant que coproc.sh:

#!/bin/bash

IFS=

run_in_coproc () {
    echo "coproc[$1] -> main"
    read -r; echo $REPLY
}

# dynamic-coprocess-generator. Nice.
_coproc () {
    local i o e n=${1//[^A-Za-z0-9_]}; shift
    exec {i}<> <(:) {o}<> >(:) {e}<> >(:)
. /dev/stdin <<COPROC "${@}"
    (("\$@")&) <&$i >&$o 2>&$e
    $n=( $o $i $e )
COPROC
}

# pi-rads-of-awesome?
for x in {0..5}; do
    _coproc COPROC$x run_in_coproc $x
    declare -p COPROC$x
done

for x in COPROC{0..5}; do
. /dev/stdin <<RUN
    read -r -u \${$x[0]}; echo \$REPLY
    echo "$x <- main" >&\${$x[1]}
    read -r -u \${$x[0]}; echo \$REPLY
RUN
done

puis

# ./coproc.sh 
declare -a COPROC0='([0]="21" [1]="16" [2]="23")'
declare -a COPROC1='([0]="24" [1]="19" [2]="26")'
declare -a COPROC2='([0]="27" [1]="22" [2]="29")'
declare -a COPROC3='([0]="30" [1]="25" [2]="32")'
declare -a COPROC4='([0]="33" [1]="28" [2]="35")'
declare -a COPROC5='([0]="36" [1]="31" [2]="38")'
coproc[0] -> main
COPROC0 <- main
coproc[1] -> main
COPROC1 <- main
coproc[2] -> main
COPROC2 <- main
coproc[3] -> main
COPROC3 <- main
coproc[4] -> main
COPROC4 <- main
coproc[5] -> main
COPROC5 <- main

Et voilà, engendrez n'importe quoi. le <(:) ouvre un canal anonyme via la substitution de processus, qui meurt, mais le canal reste collé car vous en avez le contrôle. Je fais habituellement un sleep 1 au lieu de : parce que c'est un peu rusé, et j'aurais une erreur "fichier occupé" - cela ne se produit jamais si une commande réelle est exécutée (par exemple, command true )

"sourcing heredoc":

. /dev/stdin <<EOF
[...]
EOF

Cela fonctionne sur tous les Shell que j'ai jamais essayés, y compris busybox/etc (initramfs). Je ne l'ai jamais vu faire auparavant, je l'ai découvert de manière indépendante en poussant, qui savait que la source pouvait accepter les arguments? Mais il s’agit souvent d’une forme d’évaluation beaucoup plus gérable, s’il existe.

38
anthonyrisinger
Nohup blah &

Remplacez le nom de votre processus par blah!

34
Brian Knoblauch

Personnellement, j'aime bien la commande 'batch'.

$ batch
> mycommand -x arg1 -y arg2 -z arg3
> ^D

Cela le place dans l’arrière-plan, puis vous envoie les résultats par courrier. C'est une partie de cron.

17
Will Hartung

Comme d'autres l'ont noté, pour exécuter un processus en arrière-plan afin de pouvoir vous déconnecter de votre session SSH, le processus d'arrière-plan doit être correctement dissocié de son terminal de contrôle, qui est le pseudo-tty utilisé par la session SSH.

Vous trouverez des informations sur la démonisation de processus dans des ouvrages tels que "Advanced Network Program, Vol 1, 3rd Edn" de Stevens ou "Advanced Unix Programming" de Rochkind.

J'ai récemment (au cours des deux dernières années) dû faire face à un programme récalcitrant qui ne s'est pas démonisé correctement. J'ai fini par gérer cela en créant un programme de démonisation générique - similaire à Nohup mais avec plus de contrôles disponibles.

Usage: daemonize [-abchptxV][-d dir][-e err][-i in][-o out][-s sigs][-k fds][-m umask] -- command [args...]
  -V          print version and exit
  -a          output files in append mode (O_APPEND)
  -b          both output and error go to output file
  -c          create output files (O_CREAT)
  -d dir      change to given directory
  -e file     error file (standard error - /dev/null)
  -h          print help and exit
  -i file     input file (standard input - /dev/null)
  -k fd-list  keep file descriptors listed open
  -m umask    set umask (octal)
  -o file     output file (standard output - /dev/null)
  -s sig-list ignore signal numbers
  -t          truncate output files (O_TRUNC)
  -p          print daemon PID on original stdout
  -x          output files must be new (O_EXCL)

Le double tiret est facultatif sur les systèmes n'utilisant pas la fonction GNU getopt (); cela est nécessaire (ou vous devez spécifier POSIXLY_CORRECT dans l'environnement) sous Linux, etc. Comme le double tiret fonctionne partout, il est préférable de l'utiliser.

Vous pouvez toujours me contacter (prénom point dernier nom sur gmail point com) si vous souhaitez obtenir le code source de daemonize.

Cependant, le code est maintenant (enfin) disponible sur GitHub dans mon référentiel SOQ (Stack Overflow Questions) en tant que fichier daemonize-1.10.tgz dans le sous-répertoire packages .

11
Jonathan Leffler

Sur un système basé sur Debian (sur la machine distante), installez:

Sudo apt-get install tmux

Usage:

tmux

exécuter les commandes que vous voulez

Pour renommer la session:

Ctrl + B alors $

nom du jeu

Pour sortir de la session:

Ctrl + B alors D

(cela quitte la session tmux). Ensuite, vous pouvez vous déconnecter de SSH.

Lorsque vous devez revenir/vérifier à nouveau, démarrez SSH et entrez

tmux attach nom_session

Cela vous ramènera à votre session tmux.

6
Max

Nohup est très utile si vous souhaitez enregistrer vos détails dans un fichier. Mais quand il passe en arrière-plan, vous ne pouvez pas lui donner un mot de passe si vos scripts le demandent. Je pense que vous devez essayer screen. C’est un utilitaire que vous pouvez installer sur votre distribution Linux en utilisant yum, par exemple sous CentOS yum install screen, puis accédez à votre serveur via PuTTY ou un autre logiciel, dans votre type de shell screen. Il ouvrira l'écran [0] dans PuTTY. Fais ton travail. Vous pouvez créer plus d'écran [1], d'écran [2], etc. au cours de la même session PuTTY.

Commandes de base à connaître:

Pour démarrer l'écran

écran


Pour c créer l'écran suivant

ctrl + a + c


Pour passer à l'écran n ext que vous avez créé

ctrl + a + n


Pour d etach

ctrl + a + d


Pendant le travail, fermez votre mastic. Et la prochaine fois que vous vous connecterez via le type PuTTY

écran -r

Pour vous reconnecter à votre écran, vous pouvez voir que votre processus est toujours en cours d'exécution à l'écran. Et pour quitter le type d’écran #exit.

Pour plus de détails, voir man screen.

5
Adeel Ahmad

Pour la plupart des processus, vous pouvez pseudo-démoniser en utilisant cette vieille astuce de ligne de commande Linux:

# ((mycommand &)&)

Par exemple:

# ((sleep 30 &)&)
# exit

Puis lancez une nouvelle fenêtre de terminal et:

# ps aux | grep sleep

Montre que sleep 30 est toujours en cours d'exécution.

Vous avez démarré le processus en tant qu'enfant d'un enfant et lorsque vous quittez la commande, la commande Nohup qui déclencherait normalement la fermeture du processus ne se répercute pas en cascade sur le petit-enfant, le laissant ainsi. Processus orphelin, toujours en cours d'exécution.

Je préfère cette approche "installez-le et oubliez-le", pas besoin de vous occuper de Nohup, screen, tmux, de la redirection d'E/S ou de tout ce genre de choses.

5
RAM

Nohup permet de ne pas tuer un processus client si le processus parent est tué, comme argument lorsque vous vous déconnectez. Encore mieux utiliser encore:

Nohup /bin/sh -c "echo \$\$ > $pidfile; exec $FOO_BIN $FOO_CONFIG  " > /dev/null

Nohup rend le processus que vous démarrez immunisé contre toute interruption de votre session SSH et de ses processus enfants lorsque vous vous déconnectez. La commande que j'ai donnée vous fournit un moyen de stocker le pid de l'application dans un fichier pid afin que vous puissiez le tuer correctement plus tard et permettre l'exécution du processus une fois que vous vous êtes déconnecté.

5
jcodeninja

Si vous utilisez screen pour exécuter un processus en tant que root, prenez garde à la possibilité d'attaques par élévation de privilèges. Si votre compte est compromis d'une manière ou d'une autre, il y aura un moyen direct de prendre en charge l'intégralité du serveur.

Si ce processus doit être exécuté régulièrement et que vous disposez d'un accès suffisant sur le serveur, une meilleure option serait d'utiliser cron l'exécution du travail. Vous pouvez également utiliser init.d (le super démon) pour démarrer votre processus en arrière-plan, qui peut se terminer dès que c'est fait.

5
Dana the Sane

Utilisez l'écran. Il est très simple à utiliser et fonctionne comme vnc pour les terminaux. http://www.bangmoney.org/presentations/screen.html

4
Deon

Ajoutez cette chaîne à votre commande:> & - 2> & - <& - &. > & - signifie fermer stdout. 2> & - signifie fermer stderr. <& - signifie fermer stdin. & signifie courir en arrière-plan. Cela fonctionne pour démarrer un travail par programme via ssh également:

$ ssh myhost 'sleep 30 >&- 2>&- <&- &'
# ssh returns right away, and your sleep job is running remotely
$
2
tbc0

Si vous souhaitez également exécuter des applications X, utilisez xpra avec "screen".

2
Alexey Shurygin

Il y a aussi la commande daemon du paquet libslack open-source.

daemon est tout à fait configurable et prend en charge tous les trucs fastidieux du démon tels que le redémarrage automatique, la journalisation ou la gestion du fichier pid.

2
janv

je voudrais aussi aller pour le programme d'écran (je sais que quelque autre réponse était écran mais c'est une complétion)

non seulement le fait que &, ctrl + z bg désavoué, Nohup, etc. puisse vous donner une vilaine surprise que lorsque vous vous déconnectez, un travail sera toujours tué (je ne sais pas pourquoi, mais cela m'est arrivé et cela ne m'a pas dérangé avec cela soit parce que je suis passé à l’utilisation d’écran, mais je suppose que la solution anthonyrisinger (un double fourrage résoudrait cela), les écrans ont également un avantage majeur par rapport à l’arrière-plan:

screen will background your process without losing interactive control to it

et d'ailleurs, c'est une question que je ne poserais jamais en premier lieu :) ... j'utilise l'écran depuis mon début de rien faire dans n'importe quel unix ... je (presque) ne travaille JAMAIS dans un Shell Unix/Linux sans démarrer l'écran D'abord ... et je devrais m'arrêter maintenant, ou je vais commencer une présentation sans fin de ce qu'est un bon écran et de ce que vous pouvez faire pour vous ... Regardez-le par vous-même, ça vaut le coup;)

2
THESorcerer

Sur systemd/Linux, systemd-run est un outil pratique pour lancer des processus indépendants de la session. Les haineux continueront de détester

1
Eugene Shatsky

La réponse acceptée suggère d'utiliser Nohup . Je suggérerais plutôt d'utiliser pm2 . Utiliser pm2 sur Nohup présente de nombreux avantages, tels que le maintien de l'application en vie, maintenir les fichiers de log pour l'application et beaucoup plus d'autres fonctionnalités. Pour plus de détails cochez cette case .

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

Les fichiers exécutables binaires peuvent également être exécutés à l’aide de pm2. Vous devez modifier le fichier jason. Changez le "exec_interpreter" : "node" en "exec_interpreter" : "none". (voir le section d'attributs ).

#include <stdio.h>
#include <unistd.h>  //No standard C library
int main(void)
{
    printf("Hello World\n");
    sleep (100);
    printf("Hello World\n");

    return 0;
}

Compiler le code ci-dessus

gcc -o hello hello.c  

et exécutez-le avec np2 en arrière-plan

pm2 start ./hello
1
haccks

J'ai utilisé la commande d'écran. Ce lien contient des détails sur la manière de procéder.

https://www.rackaid.com/blog/linux-screen-tutorial-and-how-to/#starting

1
Shravan Ramamurthy