Bash: Comment faire pour qu’un script se réexécute en tâche de fond?

J’écris un script Bash destiné à être utilisé comme démon. Si l’utilisateur de mon script ne transmet pas une option --sync au script, je souhaite que le script se réexécute en tant que tâche d’arrière-plan en utilisant cette option. Voici mon code (la dernière partie a été volée dans ce post SO ):

 #!/usr/bin/env bash args=("$@") # capture them here so we can use them if --sync's not passed async=true while [ $# -gt 0 ] do case "$1" in --sync) async=false ;; # other options esac shift done # if --sync isn't passed, rerun the script as a background task $async && exec nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0 /dev/null & 

Pour une raison quelconque, cela ne semble pas fonctionner. Quand je fais bash -x myscript (ce qui aide à déboguer le script), il semble que cela continue juste même si $async est vrai, ce que je ne pense pas que cela arriverait puisque exec normalement l’exécution.

De même, si je lance cette commande depuis mon terminal:

 exec nohup true 0 /dev/null & 

il ne parvient pas non plus à quitter le shell, malgré l’utilisation de exec . Pourquoi est-ce que, et que puis-je faire pour le contourner? (Points bonus: y a-t-il un moyen de le faire sans créer un sous-shell?)

Merci.

Le & est appliqué à la commande exec elle-même, donc exec foo & forks un nouveau sous-shell asynchrone (ou son équivalent, voir ci-dessous). Ce sous-shell se remplace immédiatement par foo . Si vous voulez que le parent (c’est-à-dire votre script) se termine également, vous devrez le faire explicitement avec une commande exit .

L’ exec ne vous achète probablement rien ici. Bash est assez intelligent pour ne pas réellement démarrer un sous-shell pour une simple commande d’arrière-plan. Donc ça devrait suffire à faire:

 if $async; then nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0<&- &> /dev/null & exit 0 fi 

Je ne sais pas comment faire cela sans un sous-shell. Mais lorsque vous écrivez des scripts de shell, vous obtenez des sous-couches. Personnellement, je voudrais juste utiliser une variable simple et la tester avec quelque chose comme if [[ $async ]]; au lieu d’exécuter true ou false , mais puisque ce sont aussi des bases de Bash, c’est assez bien équivalent. Dans d’autres shells, ils peuvent fonctionner dans des sous-couches.

Maintenant que j’y pense, puisque vous retraitez de toute façon toutes les options de l’exécution asynchrone, vous pourriez aussi bien quitter et sortir de la requête, vous n’avez donc pas besoin de la deuxième vérification:

 case "$1" in --sync) nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0<&- &> /dev/null & exit 0 ;; 

Je ne suis pas d’accord avec la réponse de rici parce que la question indique clairement que le contexte n’est souhaité que lorsque –sync n’est PAS transmis dans le script. Ce qui a été montré semble être une boucle infinie et ne vérifie pas tous les parameters passés. Je crois que le code original était correct, sauf pour le dernier “async && exec …”. Le remplacement suivant pour cette ligne devrait fonctionner:

 if [ "$async" = true ]; then nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0<&- &> /dev/null & exit 0 fi 

suivi de ce que votre code est censé faire lorsque –sync est passé.