J’ai récemment mis à jour mon article sur Rsync pour rapatrier quelques fichiers d’un serveur vers mon NAS Synology. Or, une question revient vite dès qu’une commande doit tourner pendant plusieurs heures : comment lancer une tâche depuis un terminal, fermer ce terminal, puis laisser la commande continuer tranquillement ?
Par défaut, ce n’est pas toujours gagné. Quand on ferme un terminal, le shell peut envoyer un signal SIGHUP aux processus qu’il a lancés. Résultat : la commande peut s’arrêter, même si elle était encore en train de travailler.
Heureusement, Bash propose plusieurs méthodes pour lancer une commande en arrière-plan, la détacher du terminal, ou même retrouver une session plus tard. Voici les solutions que je garde sous le coude.
Lancer une commande en arrière-plan avec &
La méthode la plus simple consiste à ajouter une esperluette & à la fin de la commande. Bash lance alors le processus en arrière-plan et rend immédiatement la main au terminal.
sleep 100 &
Le shell affiche alors un numéro de job et un identifiant de processus, aussi appelé PID :
[1] 12345Code language: JSON / JSON with Comments (json)
C’est pratique, mais ce n’est pas suffisant si vous voulez fermer le terminal sans risque. La commande reste encore rattachée à la session du shell.
On peut vérifier les tâches lancées depuis le shell courant avec :
jobs
Et on peut vérifier que le processus tourne toujours avec :
ps aux | grep sleep
Détacher une tâche avec disown
La commande disown permet de retirer un job de la table des tâches du shell. En clair, Bash ne le surveille plus. Ainsi, lorsque le terminal se ferme, le shell ne tente plus de gérer cette commande.
On peut lancer une commande en arrière-plan, puis la détacher immédiatement :
Marre des agences qui sous-traitent ?
Avec moi, vous parlez directement au développeur qui fait le travail. Pas d'intermédiaire, pas de promesses creuses. Juste du code propre et un interlocuteur joignable.
Travaillons directement ensemble →sleep 600 &
disown
Ou bien, plus compact :
sleep 600 & disown
À partir de là, vous pouvez fermer le terminal. Le processus devrait continuer à tourner.
Pour une vraie commande longue, comme un transfert Rsync, cela donne par exemple :
rsync -avh --progress /home/www/ user@nas:/volume1/backups/www/ & disownCode language: JavaScript (javascript)
Petit bémol tout de même : si la commande écrit dans le terminal, sa sortie peut devenir gênante, voire provoquer des comportements inattendus après la fermeture de la session. Il vaut donc mieux rediriger la sortie standard et les erreurs vers un fichier de log.
rsync -avh /home/www/ user@nas:/volume1/backups/www/ > ~/rsync-backup.log 2>&1 & disownCode language: JavaScript (javascript)
On peut ensuite suivre l’avancement avec :
tail -f ~/rsync-backup.log
Utiliser nohup
nohup signifie “no hangup”. La commande sert justement à ignorer le signal SIGHUP, souvent envoyé lorsqu’un terminal se ferme.
Exemple simple :
nohup sleep 600 &
Par défaut, nohup écrit la sortie de la commande dans un fichier nommé nohup.out, dans le répertoire courant ou dans votre dossier personnel.
Pour une commande longue, je préfère être explicite et définir moi-même le fichier de log :
nohup rsync -avh /home/www/ user@nas:/volume1/backups/www/ > ~/rsync-backup.log 2>&1 &Code language: JavaScript (javascript)
C’est simple, robuste, et suffisant pour une commande ponctuelle que l’on n’a pas besoin de reprendre en main ensuite.
Créer un sous-shell
On peut aussi lancer une commande dans un sous-shell avec des parenthèses. Le signe & lance ce sous-shell en arrière-plan, puis exit permet de quitter le terminal proprement.
(sleep 100) & exitCode language: PHP (php)
On peut ensuite ouvrir un autre terminal et vérifier que la tâche tourne toujours :
ps aux | grep sleep
Cette méthode fonctionne dans certains cas simples, mais elle reste moins explicite que nohup, disown ou screen. Pour une tâche vraiment importante, je préfère une solution plus lisible et plus facile à reprendre.
Utiliser screen pour garder une session récupérable
La commande screen change un peu d’approche. Au lieu de simplement détacher une commande, elle crée une session terminal indépendante. Vous pouvez lancer une commande dedans, vous détacher de la session, fermer votre terminal, puis revenir plus tard exactement là où vous en étiez.
C’est parfait pour les commandes longues que vous voulez surveiller, comme un rsync, une restauration de base de données, une compilation, une migration WordPress, ou un script qui affiche une progression utile.
Pour créer une session nommée :
screen -S backup-rsync
Vous vous retrouvez alors dans un nouveau terminal virtuel. Lancez votre commande normalement :
rsync -avh --progress /home/www/ user@nas:/volume1/backups/www/Code language: JavaScript (javascript)
Pour vous détacher de la session sans arrêter la commande, utilisez le raccourci suivant :
Ctrl + A, puis D
Le terminal affiche alors quelque chose comme :
[detached from 12345.backup-rsync]Code language: JSON / JSON with Comments (json)
Vous pouvez maintenant fermer le terminal. La commande continue dans la session screen.
Pour lister les sessions existantes :
screen -ls
Pour reprendre la session plus tard :
screen -r backup-rsync
Si vous n’avez qu’une seule session ouverte, cette commande suffit souvent :
screen -r
Enfin, pour quitter définitivement une session screen, il suffit de terminer la commande en cours, puis de taper :
exitCode language: PHP (php)
screen est donc la meilleure option lorsque vous voulez pouvoir revenir dans votre terminal plus tard. Contrairement à nohup ou disown, vous ne vous contentez pas de lancer une tâche dans le vide : vous gardez une vraie session interactive.
Quelle méthode choisir ?
Pour une commande rapide que vous voulez simplement envoyer en arrière-plan, & suffit.
Pour une commande ponctuelle qui doit continuer après la fermeture du terminal, nohup avec une redirection vers un fichier de log reste une valeur sûre.
Pour une commande déjà lancée en arrière-plan, disown permet de la détacher du shell courant.
Enfin, pour une tâche longue que vous voulez pouvoir suivre et reprendre plus tard, screen est beaucoup plus confortable.
Dans mon cas, pour un gros transfert rsync, j’utilise généralement screen. C’est plus propre, plus lisible, et surtout moins stressant quand la copie dure plusieurs heures. Fermer un terminal sans faire tomber une sauvegarde, c’est tout de même meilleur pour le rythme cardiaque.
Mémo rapide
# Lancer en arrière-plan.
commande &
# Lancer en arrière-plan puis détacher du shell.
commande & disown
# Ignorer la fermeture du terminal et écrire dans un log.
nohup commande > ~/commande.log 2>&1 &
# Créer une session screen nommée.
screen -S nom-session
# Se détacher d'une session screen.
Ctrl + A, puis D
# Lister les sessions screen.
screen -ls
# Reprendre une session screen.
screen -r nom-sessionCode language: PHP (php)
À garder sous le coude.
Besoin d'un coup de main ?
Ce bug qui traîne depuis des semaines, ce plugin qui casse votre mise en page, cette fonctionnalité que personne n'arrive à implémenter proprement — c'est exactement ce que je règle au quotidien depuis 20 ans.
Parlons de votre problème →
Y’a aussi avec screen, qui permet de créer des terminaux “virtuels”:
screen -S rsync
*on lace rsync etc*
Pour revenir au terminal principal : ctrl+a, d
Et pour revenir sur rsync : screen -r rsync
Merci Angristan pour l’alternative avec
screen!