bash:默默杀死后台功能进程

时间:2011-04-19 15:43:32

标签: linux bash shell unix scripting

shell大师,

我有一个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

这完全摧毁了我的,非常酷的进度条显示的精彩。

如何摆脱此消息?

11 个答案:

答案 0 :(得分:56)

kill $foo_pid
wait $foo_pid 2>/dev/null
顺便说一句,我不知道你那个非常酷的进度条,但你见过Pipe Viewer(pv)吗? http://www.ivarch.com/programs/pv.shtml

答案 1 :(得分:27)

我自己也遇到了这个问题,并意识到" disown"是我们正在寻找的。

foo &
foo_pid=$!
disown

boring_and_long_command
kill $foo_pid
sleep 10

正在打印死亡消息,因为该过程仍在被监视的" jobs"的shell列表中。 disown命令将从此列表中删除最近生成的进程,以便在被杀死时不会生成调试消息,即使使用SIGKILL(-9)也是如此。

答案 2 :(得分:5)

尝试使用以下行替换您的行kill $foo_pid >/dev/null 2>&1

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

<强>更新

这个答案不正确的原因是@ mklement0在他的评论中解释的原因:

  

这个答案对后台工作无效的原因是   kill命令完成后,异步Bash自身,   输出有关已杀死作业的状态消息,您不能这样做   直接抑制 - 除非你使用等待,如接受的答案。

答案 3 :(得分:4)

这是我为类似问题提出的解决方案(想要在长时间运行的进程中显示时间戳)。这实现了一个killsub函数,只要你知道pid就可以安静地杀死任何子shell。请注意,陷阱指令非常重要:如果脚本中断,子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

答案 4 :(得分:3)

这种“黑客”似乎有效:

# 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

它的灵感来自于here。世界秩序已经恢复。

答案 5 :(得分:1)

在功能开始时添加:

trap 'exit 0' TERM

答案 6 :(得分:0)

关于使用'等待':这是我认为最好的答案。 有关此外观/工作方式的示例,请参阅https://stackoverflow.com/a/10200191/1208218

答案 7 :(得分:0)

另一种方法:

    func_terminate_service(){

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

    }

调用它
    func_terminate_service "firefox"

答案 8 :(得分:0)

禁用作业通知的另一种方法是将命令置于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

答案 9 :(得分:0)

您可以在使用set +m之前禁止它。有关here

的更多信息

答案 10 :(得分:0)

错误消息应该来自在脚本中转储信号源的默认信号处理程序。我只在 bash 3.x 和 4.x 上遇到过类似的错误。为了始终在任何地方安静地杀死子进程(在 bash 3/4/5、dash、ash、zsh 上测试),我们可以在子进程的第一个处捕获 TERM 信号:

#!/bin/sh

## assume script name is test.sh

foo() {
  trap 'exit 0' TERM ## here is the key
  while true; do sleep 1; done
}

echo before child
ps aux | grep 'test\.s[h]\|slee[p]'

foo &
foo_pid=$!

sleep 1 # wait trap is done

echo before kill
ps aux | grep 'test\.s[h]\|slee[p]'

kill $foo_pid

sleep 1 # wait kill is done

echo after kill
ps aux | grep 'test\.s[h]\|slee[p]'

相关问题