Lancer une commande longue avec mon-script.sh & puis fermer le terminal SSH tue quand même le script, malgré le & censé le faire tourner en arrière-plan. Le & détache la commande du premier plan du shell, mais ne la protège en rien contre ce qui se passe quand le shell lui-même se termine.
Ce qui se passe réellement à la déconnexion
Quand une session shell se termine (fermeture du terminal, coupure SSH), le kernel envoie SIGHUP (hangup) à tous les processus enfants de ce shell, arrière-plan compris. Un processus qui ne gère pas explicitement ce signal se termine à sa réception, exactement comme il se terminerait sur un SIGTERM sans trap pour l’intercepter.
# Le & met en arrière-plan, mais ne protège
# absolument pas contre SIGHUP à la déconnexion
mon-script-long.sh &
exit
# → mon-script-long.sh reçoit SIGHUP et se termine
nohup : ignorer explicitement SIGHUP
nohup lance une commande en configurant explicitement l’ignorance du signal SIGHUP, avant même que le processus ne démarre : la déconnexion du shell n’a alors plus aucun effet sur lui, la sortie standard étant redirigée par défaut vers un fichier nohup.out puisque le terminal qui l’affichait n’existera plus.
# Immunisé contre SIGHUP dès le lancement,
# la sortie va dans nohup.out par défaut
nohup mon-script-long.sh &
disown : protéger un processus déjà lancé
disown s’applique après coup, sur un processus déjà en arrière-plan dans le shell courant : il retire ce processus de la table des jobs du shell, ce qui l’empêche de recevoir le SIGHUP que le shell propage normalement à ses enfants lors de sa propre terminaison.
mon-script-long.sh &
disown
# Le shell peut maintenant se fermer,
# le processus continue sans recevoir SIGHUP
setsid : la protection la plus radicale
setsid lance une commande dans une toute nouvelle session, détachée de tout terminal contrôlant dès l’origine : sans terminal contrôlant, il n’y a structurellement personne pour envoyer SIGHUP à ce processus, une garantie plus forte que nohup (qui ignore le signal) ou disown (qui empêche sa propagation), puisque la relation qui produirait ce signal n’existe simplement jamais.
À retenir
Le & détache une commande du premier plan du shell mais ne la protège pas contre SIGHUP, le signal envoyé par le kernel à tous les enfants d’un shell à sa terminaison, y compris ceux mis en arrière-plan. nohup fait ignorer ce signal dès le lancement, disown retire après coup un processus déjà lancé de la table des jobs pour éviter qu’il ne le reçoive, et setsid offre la garantie la plus solide en détachant le processus de tout terminal contrôlant dès l’origine. Le bon outil dépend du moment : avant le lancement pour nohup ou setsid, après coup pour disown sur un processus déjà en cours.