Linux sans magie #22 — nohup et disown : garder une commande active après la fermeture du terminal

Comprendre SIGHUP, nohup et disown dans Bash, savoir ce que chacun protège réellement et éviter de confondre processus détaché et session terminal persistante.

Dans l’article sur les jobs du shell, nous avons vu comment lancer une commande en arrière-plan avec &, la suspendre, puis la reprendre avec fg ou bg. Mais une question reste entière : que se passe-t-il si le terminal disparaît ou si le shell se termine alors qu’un travail est encore en cours ?

C’est là qu’apparaissent SIGHUP, nohup et disown.

Ces notions sont souvent résumées par « faire tourner une commande après la déconnexion ». Ce raccourci masque une différence importante : nohup agit sur la façon dont une commande traite le signal de hangup, tandis que disown agit sur la façon dont Bash suit un job et lui transmet éventuellement SIGHUP.

L’objectif est de comprendre cette différence, d’utiliser les deux mécanismes proprement et de savoir quand ils ne suffisent plus.

Contexte : arrière-plan ne veut pas dire indépendant

Prenons une commande simple :

sleep 300 &

Elle tourne en arrière-plan, mais elle reste un job connu du shell courant.

Vérifiez :

jobs -l

Puis récupérez son PID :

pid=$!

Le fait d’avoir ajouté & ne rend donc pas automatiquement la commande indépendante de la session.

Si le terminal disparaît ou si le shell reçoit un signal de hangup, le comportement dépend notamment du shell, de son job control et de la disposition du signal dans le processus concerné.

SIGHUP : le signal de hangup

Historiquement, SIGHUP signifie hangup : la disparition d’une connexion terminal. Sous Linux, il reste utilisé dans ce contexte, même si certains programmes lui donnent aussi une signification applicative, par exemple recharger leur configuration.

SIGHUP n’est donc pas synonyme de « tuer le processus ». C’est un signal dont l’effet dépend de la disposition choisie par le processus : comportement par défaut, gestionnaire spécifique ou signal ignoré.

Bash ajoute une couche supplémentaire. Lorsqu’un shell interactif reçoit SIGHUP avant de quitter, il renvoie ce signal à ses jobs, qu’ils soient en cours d’exécution ou stoppés. Bash permet d’influencer ce comportement avec disown.

C’est pourquoi mettre une commande en arrière-plan avec & ne constitue pas à lui seul une protection contre la disparition de la session.

nohup : ignorer le hangup dès le lancement

GNU nohup lance une commande avec le signal de hangup ignoré.

Forme générale :

nohup commande arguments

Exemple :

nohup sleep 300

Point essentiel : nohup ne place pas automatiquement la commande en arrière-plan.

Pour récupérer immédiatement le prompt :

nohup sleep 300 &

Dans une procédure d’exploitation, mieux vaut aussi gérer explicitement les sorties :

nohup sleep 300 > /tmp/nohup-lab.log 2>&1 &
pid=$!

Puis vérifiez :

ps -p "$pid" -o pid,ppid,stat,comm

Que fait nohup des entrées et sorties ?

GNU Coreutils adapte également les descripteurs associés à un terminal.

Si l’entrée standard est un terminal, GNU nohup la redirige afin d’éviter que la commande continue à attendre une saisie sur ce terminal. Si la sortie standard est encore un terminal, elle est normalement redirigée vers nohup.out, ou vers $HOME/nohup.out si nécessaire. La sortie d’erreur est elle aussi adaptée lorsqu’elle pointe vers le terminal.

Une redirection explicite reste plus lisible :

nohup ./traitement.sh > /var/tmp/traitement.log 2>&1 &

On sait alors immédiatement où chercher la sortie.

disown : modifier la relation entre Bash et un job

disown est un builtin de Bash. Il agit donc sur la table des jobs du shell courant.

Lancez un job et conservez son PID :

sleep 300 &
pid=$!

Vérifiez qu’il est connu de Bash :

jobs -l

Le job tout juste lancé est normalement le job courant. Pour éviter de dépendre d’un numéro comme %1, utilisez le jobspec %+ :

disown %+

Puis :

jobs

Le job ne doit plus apparaître dans la table du shell.

Le processus peut pourtant toujours exister :

ps -p "$pid" -o pid,ppid,stat,comm

C’est une distinction fondamentale : la table des jobs de Bash et la table des processus du noyau ne sont pas la même chose.

Après un disown, les commandes jobs, fg et bg de ce shell ne permettent plus de piloter ce processus comme un job. Il faut utiliser son PID ou d’autres outils de gestion de processus.

disown -h : garder le job, mais ne pas lui relayer SIGHUP

Bash propose aussi :

disown -h %+

Avec -h, le job n’est pas supprimé de la table. Il est marqué afin que Bash ne lui envoie pas SIGHUP si le shell reçoit lui-même SIGHUP.

Vous pouvez donc encore le voir avec :

jobs -l

La règle pratique est :

disown %+      → retire le job courant de la table de Bash

disown -h %+   → conserve le job, mais demande à Bash de ne pas lui relayer SIGHUP

Cela ne transforme pas le processus en service système. Il reste un processus ordinaire avec son environnement et ses propres contraintes.

nohup et disown ne sont pas équivalents

Les deux outils sont parfois présentés comme interchangeables. Techniquement, ce n’est pas exact.

nohup intervient au lancement de la commande : il configure SIGHUP pour être ignoré et adapte, si nécessaire, les entrées/sorties liées au terminal.

disown intervient dans Bash sur un job déjà lancé : il modifie le suivi de ce job ou la manière dont Bash lui transmettra SIGHUP.

Exemple avec nohup :

nohup ./traitement.sh > /var/tmp/traitement.log 2>&1 &

Exemple avec disown après avoir déjà lancé la commande :

./traitement.sh > /var/tmp/traitement.log 2>&1 &
pid=$!
disown %+

Le deuxième cas peut être utile, mais disown ne reproduit pas les adaptations d’entrées/sorties effectuées par nohup.

Lab : observer la différence sans fermer sa session

Le lab utilise uniquement sleep et ne modifie aucun service.

1. Tester nohup

nohup sleep 300 > /tmp/nohup-lab.log 2>&1 &
pid=$!

Vérifiez :

ps -p "$pid" -o pid,ppid,stat,comm
jobs -l

Le processus doit être visible. Le shell peut encore le connaître comme job tant qu’il n’a pas été retiré de sa table.

Nettoyez :

kill "$pid"
wait "$pid" 2>/dev/null || true
rm -f /tmp/nohup-lab.log

2. Tester disown

sleep 300 &
pid=$!
jobs -l

Retirez le job courant de la table de Bash :

disown %+

Comparez ensuite les deux vues :

jobs
ps -p "$pid" -o pid,ppid,stat,comm

Le résultat attendu est instructif : le job a disparu de la vue de Bash, mais le processus existe toujours.

Comme le shell ne le connaît plus comme job, nettoyez avec le PID conservé :

kill "$pid"
ps -p "$pid"

Le processus ne doit plus apparaître après sa terminaison.

Tester réellement une déconnexion

Un vrai test de déconnexion doit être réalisé dans une session de laboratoire distincte, idéalement une session SSH non critique.

Lancez par exemple :

nohup sleep 600 > /tmp/nohup-test.log 2>&1 &
echo $! > /tmp/nohup-test.pid

Fermez ensuite volontairement cette session de test, reconnectez-vous par une autre session, puis vérifiez :

pid=$(cat /tmp/nohup-test.pid)
ps -p "$pid" -o pid,ppid,stat,comm

Nettoyez ensuite :

kill "$pid" 2>/dev/null || true
rm -f /tmp/nohup-test.pid /tmp/nohup-test.log

Ce test doit rester un exercice de laboratoire : ne fermez pas une session de production importante uniquement pour observer SIGHUP.

Bonnes pratiques

Pour une commande ponctuelle non interactive, une forme explicite reste facile à relire :

nohup commande > fichier.log 2>&1 &

Conservez le PID si vous devrez vérifier ou arrêter le processus :

pid=$!

Ne comptez pas uniquement sur jobs : après disown ou après une nouvelle connexion, la table de jobs du shell d’origine n’est plus disponible.

Évitez également d’utiliser nohup avec une application réellement interactive. Une commande privée de son terminal mais qui attend encore un dialogue utilisateur devient difficile à exploiter correctement.

Pour un traitement durable, redémarrable, surveillé ou nécessaire au démarrage de la machine, une unité systemd est généralement plus adaptée : état, redémarrage, journalisation, dépendances et politique de démarrage sont gérés explicitement.

Sécurité et exploitation

Un processus lancé avec nohup conserve les droits de l’utilisateur qui l’a lancé. nohup n’ajoute aucun privilège.

La redirection des sorties mérite aussi une attention particulière. Ne placez pas de secrets dans une ligne de commande ou dans un fichier de log simplement parce que le traitement s’exécute en arrière-plan.

Si vous choisissez vous-même un fichier de sortie, vérifiez son emplacement et ses permissions :

ls -l /var/tmp/traitement.log

Pour des traitements sensibles, utilisez un répertoire et des permissions adaptés plutôt que /tmp ou /var/tmp par réflexe.

Limites : ce que nohup et disown ne font pas

nohup et disown ne créent pas une session terminal persistante.

Ils ne permettent pas de fermer un terminal puis de retrouver plus tard exactement le même environnement interactif. Ils ne fournissent pas non plus plusieurs fenêtres, plusieurs panneaux ou un rattachement interactif à une session existante.

Pour conserver une session terminal interactive que l’on peut détacher puis rattacher, les outils adaptés sont notamment screen et tmux. Ce sera le sujet du prochain article.

Autre limite : le comportement complet lors de la disparition d’un terminal implique plusieurs couches — terminal, shell, job control, sessions, groupes de processus et application. Ici, nous restons volontairement au niveau opérationnel de Bash, nohup et disown.

Rollback et nettoyage

Pour terminer un processus dont vous avez conservé le PID :

kill "$pid"

Vérifiez :

ps -p "$pid"

Puis supprimez les fichiers temporaires du lab :

rm -f /tmp/nohup-lab.log /tmp/nohup-test.log /tmp/nohup-test.pid

Aucun service ni fichier de configuration permanent n’est modifié.

Références officielles

Conclusion

Mettre une commande en arrière-plan avec & et la rendre moins dépendante de la session sont deux problèmes différents.

nohup lance une commande en lui faisant ignorer le signal de hangup et adapte si nécessaire ses entrées/sorties liées au terminal. disown agit dans Bash : il retire un job de la table du shell ou, avec -h, demande à Bash de ne pas lui relayer SIGHUP.

Pour une tâche ponctuelle non interactive, ces mécanismes peuvent être parfaitement adaptés. Pour un service durable, systemd est généralement plus approprié. Et pour conserver une véritable session terminal interactive que l’on pourra retrouver plus tard, il faut changer d’outil : ce sera le rôle de screen et tmux dans Linux sans magie #23.