web-dev-qa-db-fra.com

bash: tue silencieusement le processus de fonction d'arrière-plan

Gourous des coquillages,

J'ai un script shell bash, dans lequel je lance une fonction d'arrière-plan, disons foo(), pour afficher une barre de progression pour une commande longue et ennuyeuse:

foo()
{
    while [ 1 ]
    do
        #massively cool progress bar display code
        sleep 1
    done
}

foo &
foo_pid=$!

boring_and_long_command
kill $foo_pid >/dev/null 2>&1
sleep 10

maintenant, quand foo meurt, je vois le texte suivant:

/home/user/script: line XXX: 30290 Killed                  foo

Cela détruit totalement l'impressionnant affichage de ma barre de progression, autrement très cool.

Comment puis-je me débarrasser de ce message?

54
rouble
kill $foo_pid
wait $foo_pid 2>/dev/null

BTW, je ne connais pas votre barre de progression extrêmement cool, mais avez-vous vu Pipe Viewer (pv)? http://www.ivarch.com/programs/pv.shtml

58
Mark Edgar

Je viens de le découvrir moi-même et j'ai réalisé que "renier" est ce que nous recherchons.

foo &
foo_pid=$!
disown

boring_and_long_command
kill $foo_pid
sleep 10

Le message de mort est en cours d'impression car le processus figure toujours dans la liste des "jobs" surveillés. La commande disown supprimera le processus généré le plus récemment de cette liste afin qu'aucun message de débogage ne soit généré lorsqu'il est tué, même avec SIGKILL (-9).

29
pix

Essayez de remplacer votre ligne kill $foo_pid >/dev/null 2>&1 avec la ligne:

(kill $foo_pid 2>&1) >/dev/null

Mise à jour:

Cette réponse n'est pas correcte pour la raison expliquée par @ mklement0 dans son commentaire:

La raison pour laquelle cette réponse n'est pas efficace avec les travaux en arrière-plan est que Bash lui-même de manière asynchrone, une fois la commande kill terminée, génère un message d'état sur le travail tué, que vous ne pouvez pas supprimer directement - sauf si vous utilisez wait, comme dans la réponse acceptée.

5
Sergei Kurenkov

C'est une solution que j'ai trouvée pour un problème similaire (je voulais afficher un horodatage pendant les processus de longue durée). Cela implémente une fonction killsub qui vous permet de tuer tranquillement n'importe quel sous-shell tant que vous connaissez le pid. Notez que les instructions d'interruption sont importantes à inclure: dans le cas où le script est interrompu, le sous-shell ne continuera pas à s'exécuter.

foo()
{
    while [ 1 ]
    do
        #massively cool progress bar display code
        sleep 1
    done
}

#Kills the sub process quietly
function killsub() 
{

    kill -9 ${1} 2>/dev/null
    wait ${1} 2>/dev/null

}

foo &
foo_pid=$!

#Add a trap incase of unexpected interruptions
trap 'killsub ${foo_pid}; exit' INT TERM EXIT

boring_and_long_command

#Kill foo after finished
killsub ${foo_pid}

#Reset trap
trap - INT TERM EXIT
4
bbbco

Ce "hack" semble fonctionner:

# Some trickery to hide killed message
exec 3>&2          # 3 is now a copy of 2
exec 2> /dev/null  # 2 now points to /dev/null
kill $foo_pid >/dev/null 2>&1
sleep 1            # sleep to wait for process to die
exec 2>&3          # restore stderr to saved
exec 3>&-          # close saved version

et il a été inspiré de ici . L'ordre mondial a été rétabli.

3
rouble

Ajoutez au début de la fonction:

trap 'exit 0' TERM
2
jilles

En ce qui concerne l'utilisation de "attendre": c'est la meilleure réponse, je pense. Voir https://stackoverflow.com/a/10200191/1208218 pour un exemple de la façon dont cela ressemble/fonctionne.

0
Roel

Vous pouvez utiliser set +m avant de supprimer cela. Plus d'informations à ce sujet ici

0
AhmadAssaf

Une autre façon de procéder:

    func_terminate_service(){

      [[ "$(pidof ${1})" ]] && killall ${1}
      sleep 2
      [[ "$(pidof ${1})" ]] && kill -9 "$(pidof ${1})" 

    }

appeler avec

    func_terminate_service "firefox"
0
Mike Q

Une autre façon de désactiver les notifications de tâche consiste à placer votre commande en arrière-plan dans un sh -c 'cmd &' construire.

#!/bin/bash

foo()
{
   while [ 1 ]
   do
       sleep 1
   done
}

#foo &
#foo_pid=$!

export -f foo
foo_pid=`sh -c 'foo & echo ${!}' | head -1`

# if Shell does not support exporting functions (export -f foo)
#arg1='foo() { while [ 1 ]; do sleep 1; done; }'
#foo_pid=`sh -c 'eval "$1"; foo & echo ${!}' _ "$arg1" | head -1`


sleep 3
echo kill ${foo_pid}
kill ${foo_pid}
sleep 3
exit
0
phily