linux-bash:静默杀死后台功能进程
贝壳大师
我有一个bash shell脚本,在其中我启动一个后台功能,例如foo(),以显示一个无聊且冗长的命令的进度条:
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
现在,当foo死亡时,我看到以下文本:
/home/user/script: line XXX: 30290 Killed foo
这完全破坏了我本来非常棒的进度条显示的出色功能。
我如何摆脱此消息?
9个解决方案
60 votes
kill $foo_pid
wait $foo_pid 2>/dev/null
顺便说一句,我不知道您的进度栏多么酷,但是您看过Pipe Viewer(pv)吗? [http://www.ivarch.com/programs/pv.shtml]
Mark Edgar answered 2019-12-24T04:54:28Z
30 votes
刚遇到这个我自己,并意识到“寻找”是我们想要的。
foo &
foo_pid=$!
disown
boring_and_long_command
kill $foo_pid
sleep 10
正在打印死亡消息,因为该过程仍在受监视的“作业”的外壳列表中。 disown命令将从该列表中删除最近产生的进程,以便杀死它时即使使用SIGKILL(-9)也不会生成任何调试消息。
pix answered 2019-12-24T04:54:52Z
5 votes
这是我针对类似问题提出的解决方案(希望在长时间运行的过程中显示时间戳)。 这实现了killsub函数,该函数允许您只要知道pid即可安静地杀死任何子shell。 请注意,陷阱指令必须包括以下内容:如果脚本被中断,则子外壳程序将不会继续运行。
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
bbbco answered 2019-12-24T04:55:13Z
5 votes
尝试用以下行替换您的行kill $foo_pid >/dev/null 2>&1:
(kill $foo_pid 2>&1) >/dev/null
更新:
由于@ mklement0在他的评论中解释的原因,此答案不正确:
此答案对后台作业无效的原因是 在kill命令完成后,异步Bash自身, 输出有关已终止作业的状态消息,您不能 直接抑制-除非您使用wait,如接受的答案所示。
Sergei Kurenkov answered 2019-12-24T04:55:47Z
3 votes
这种“ hack”似乎有效:
# 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
从这里得到启发。 世界秩序已恢复。
rouble answered 2019-12-24T04:56:11Z
2 votes
在函数开始处添加:
trap 'exit 0' TERM
jilles answered 2019-12-24T04:56:31Z
0 votes
另一种方法是:
func_terminate_service(){
[[ "$(pidof ${1})" ]] && killall ${1}
sleep 2
[[ "$(pidof ${1})" ]] && kill -9 "$(pidof ${1})"
}
用它来称呼它
func_terminate_service "firefox"
Mike Q answered 2019-12-24T04:56:55Z
0 votes
禁用作业通知的另一种方法是将您的命令放置在sh -c 'cmd &'构造中。
#!/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
phily answered 2019-12-24T04:57:15Z
0 votes
您可以先使用set +m来取消抑制。 有关此的更多信息
AhmadAssaf answered 2019-12-24T04:57:36Z