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?
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
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).
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.
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
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.
Ajoutez au début de la fonction:
trap 'exit 0' TERM
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.
Vous pouvez utiliser set +m
avant de supprimer cela. Plus d'informations à ce sujet ici
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"
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