Pourquoi la fonction ne revient-elle pas avant la fin du processus d'arrière-plan?

21

Considérez ce script:

#!/bin/bash
function start {
  leafpad &
  echo $!
}
PID=$(start)
echo "PID is $PID"

Le script ne continue pas au-delà de son accolade fermante jusqu'à la fin du processus du pavé feuille, même s'il s'agit d'un processus d'arrière-plan.

Pourquoi est-ce? Est-il possible de lancer un processus d'arrière-plan à partir d'une fonction?

user234565
la source

Réponses:

22

La fonction renvoie, mais la substitution de commandes bloque, car vous avez créé un travail en arrière-plan, mais votre stdout fd est toujours ouvert. Fermez-le simplement en ajoutant >/dev/nullavant le &.

#!/bin/bash
function start {
  leafpad >/dev/null &
  echo $!
}
PID=$(start)
echo "PID is $PID"

Si vous souhaitez que votre processus ait également stdin, stdout, stderr fermé, utilisez ceci:

leafpad >/dev/null 0>&1 2>&1 &

Cela fermera stdin (0), stdout (1) et stderr (2), puis l'arrière-plan (&). De plus, lorsque vous utilisez ces redirections de flux, n'oubliez pas qu'elles sont "dupées", c'est-à-dire dupliquées dans l'ordre d'exécution.

1>/dev/null 2>&1

et

2>&1 1>/dev/null

ne sont pas les mêmes ! Dans le premier, vous dupliquez un flux vers / dev / null (ce que vous voulez), dans le second, vous dupliquez / dev / stdout vers stderr, puis fermez stdout. Ainsi, tout message envoyé à stderrapparaîtra dans votre console.

Adrien M.
la source
Confirmé sur mon système
user120161
10
Vous ne fermez pas les flux, vous les redirigez.
dcat
4
fermer; n>&-nest le descripteur de fichier.
dcat
1
@dcat: Oui, mais la redirection vers / depuis /dev/nullne provoquera pas d'erreurs d' E / S lorsqu'un processus essaiera d'écrire sa sortie standard, mais trouvera qu'il 1s'agit d'un FD non valide. Donc, la terminologie dans le message est erronée, pas la programmation bash réelle. (En fait, la duplication de FD 1 à 0 signifie que stdin sera un descripteur de fichier ouvert avec O_RDONLY, ce qui donnera probablement une erreur (plutôt que le nombre d'octets disponible disponible) lorsque le processus essaiera de lire.) Par exemple wc >/dev/null 0>&1->wc: standard input: Bad file descriptor
Peter Cordes
1
@PeterCordes - La fermeture de l'ancien descripteur et la redirection du nouveau ne doivent pas être mutuellement exclusives. exec <&- >&- <>/dev/null >&0gère stdin / out assez exhaustivement. Cela fait une différence dans zshau moins ce qui va concaténer toutes les ouvertures sur le même descripteur automatiquement lorsque multios est défini.
mikeserv