web-dev-qa-db-fra.com

Exécution de commandes bash en arrière-plan sans impression du travail et des identifiants de processus

Exécuter un processus en arrière-plan dans bash est assez facile.

$ echo "Hello I'm a background task" &
[1] 2076
Hello I'm a background task
[1]+  Done                    echo "Hello I'm a background task"

Cependant, la sortie est détaillée. Sur la première ligne est imprimé l'ID du travail et l'ID du processus de la tâche d'arrière-plan, puis nous avons la sortie de la commande, enfin nous avons l'ID du travail, son statut et la commande qui a déclenché le travail.

Existe-t-il un moyen de supprimer la sortie de l'exécution d'une tâche en arrière-plan de telle sorte que la sortie ressemble exactement à ce qu'elle serait sans l'esperluette à la fin? C'est à dire:

$ echo "Hello I'm a background task" &
Hello I'm a background task

La raison pour laquelle je demande est que je veux exécuter un processus d'arrière-plan dans le cadre d'une commande de tabulation afin que la sortie de cette commande soit ininterrompue pour avoir un sens.

62
Alex Spurling

Pas lié à l'achèvement, mais vous pouvez supprimer cette sortie en plaçant l'appel dans un sous-shell:

(echo "Hello I'm a background task" &)
76
Dimitre Radoulov

Dans certaines versions plus récentes de bash et dans ksh93, vous pouvez l'entourer d'un sous-shell ou d'un groupe de processus (c'est-à-dire { ... }).

/home/shellter $ { echo "Hello I'm a background task" & } 2>/dev/null
Hello I'm a background task
/home/shellter $
11
shellter

À partir de la réponse de @ shellter, cela a fonctionné pour moi:

tyler@Tyler-Linux:~$ { echo "Hello I'm a background task" & disown; } 2>/dev/null; sleep .1;
Hello I'm a background task
tyler@Tyler-Linux:~$

Je ne connais pas le raisonnement derrière cela, mais je me suis souvenu d'un ancien post qui reniait empêcher bash de sortir les identifiants de processus.

10
Tyzoid

En s'appuyant sur la réponse ci-dessus, si vous devez autoriser stderr à passer à partir de la commande:

f() { echo "Hello I'm a background task" >&2; }
{ f 2>&3 &} 3>&2 2>/dev/null
6
pajamian

Sur la base de cette réponse , je suis venu avec le plus concis et correct:

silent_background() {
    { 2>&3 "$@"& } 3>&2 2>/dev/null
    disown &>/dev/null  # Prevent whine if job has already completed
}
silent_background date
5
Tom Hale

Désolé pour la réponse à un ancien post, mais je pense que cela est utile aux autres, et c'est la première réponse sur Google.

J'avais un problème avec cette méthode (sous-coquilles) et j'utilisais 'wait'. Cependant, comme je l'exécutais dans une fonction, j'ai pu le faire:

function a {
    echo "I'm background task $1"
    sleep 5
}

function b {
    for i in {1..10}; do
        a $i &
    done
    wait
} 2>/dev/null

Et quand je le lance:

$ b
I'm background task 1
I'm background task 3
I'm background task 2
I'm background task 4
I'm background task 6
I'm background task 7
I'm background task 5
I'm background task 9
I'm background task 8
I'm background task 10

Et il y a un délai de 5 secondes avant de récupérer mon invite.

4
The Tomahawk

Essayer:

user@Host:~$ read < <( echo "Hello I'm a background task" & echo $! )
user@Host:~$ echo $REPLY
28677

Et vous avez caché à la fois le sortie et le PID . Notez que vous pouvez toujours récupérer le PID à partir de $ REPLY

4
mark_infinite

La solution de sous-shell fonctionne, mais je voulais également pouvoir attendre les travaux en arrière-plan (et ne pas avoir le message "Terminé" à la fin). $! à partir d'un sous-shell n'est pas "en attente" dans le shell interactif actuel. La seule solution qui a fonctionné pour moi a été d'utiliser ma propre fonction d'attente, qui est très simple:

myWait() {
  while true; do
    sleep 1; STOP=1
    for p in $*; do
      ps -p $p >/dev/null && STOP=0 && break
    done
    ((STOP==1)) && return 0
  done
}

i=0
((i++)); p[$i]=$(do_whatever1 & echo $!)
((i++)); p[$i]=$(do_whatever2 & echo $!)
..
myWait ${p[*]}

Assez facile.

1
ExpertNoob1