如何在bash中杀死后禁止终止消息?

时间:2008-09-17 09:40:10

标签: bash unix shell

如何抑制杀死后出现的Terminated消息 bash脚本中的进程?

我尝试了set +bm,但这不起作用。

我知道另一种解决方案涉及调用exec 2> /dev/null,但就是这样 可靠?如何重新设置它以便我可以继续查看stderr?

13 个答案:

答案 0 :(得分:118)

要使消息静音,您必须在生成消息时重定向stderr 。由于kill命令发送信号并且不等待目标进程响应,因此重定向stderr命令的kill对您没有好处。 bash builtin wait专门用于此目的。

这是一个非常简单的示例,可以杀死最新的后台命令。 (Learn more about $! here.

kill $!
wait $! 2>/dev/null

由于killwait都接受多个pid,您还可以执行批量处理。这是一个杀死所有后台进程的例子(当然是当前进程/脚本)。

kill $(jobs -rp)
wait $(jobs -rp) 2>/dev/null

我是从bash: silently kill background function process来到这里的。

答案 1 :(得分:16)

简短的回答是,你不能。 Bash始终打印前台作业的状态。监视标志仅适用于后台作业,仅适用于交互式shell,而不适用于脚本。

请参阅jobs.c中的notify_of_job_status()。

正如您所说,您可以重定向,因此标准错误指向/ dev / null,但您会错过任何其他错误消息。您可以通过在运行脚本的子shell中执行重定向来使其成为临时的。这样就留下了原始环境。

(script 2> /dev/null)

将丢失所有错误消息,但只是来自该脚本,而不是来自该shell中运行的任何其他内容。

您可以通过重定向新的文件描述符来保存和恢复标准错误:

exec 3>&2          # 3 is now a copy of 2
exec 2> /dev/null  # 2 now points to /dev/null
script             # run script with redirected stderr
exec 2>&3          # restore stderr to saved
exec 3>&-          # close saved version

但是我不建议这样做 - 第一个的唯一好处是它保存了一个子shell调用,同时更复杂,甚至可能改变脚本的行为,如果脚本改变了文件描述符


修改

有关Mark Edgar

给出的更合适的答案检查答案

答案 2 :(得分:15)

MarcH’s answer的启发。我正在使用kill -INT,因为他建议取得一些成功,但我注意到它并没有杀死一些进程。在测试了一些其他信号后,我发现SIGPIPE也会在没有消息的情况下终止。

kill -PIPE

或只是

kill -13

答案 3 :(得分:8)

解决方案:使用SIGINT(仅适用于非交互式shell)

演示:

cat > silent.sh <<"EOF"
sleep 100 &
kill -INT $!
sleep 1
EOF

sh silent.sh

http://thread.gmane.org/gmane.comp.shells.bash.bugs/15798

答案 4 :(得分:4)

也许通过调用disown

将进程从当前shell进程中分离出来

答案 5 :(得分:1)

这是我们都在寻找的吗?

不想要:

$ sleep 3 &
[1] 234
<pressing enter a few times....>
$
$
[1]+  Done                    sleep 3
$

通缉:

$ (set +m; sleep 3 &)
<again, pressing enter several times....>
$
$
$
$
$

如您所见,没有工作结束消息。在bash脚本中也适用于我,也适用于被杀死的后台进程。

'set + m'禁用当前shell的作业控制(请参阅“帮助集”)。因此,如果您在子shell中输入命令(如括号中所示),则不会影响当前shell的作业控制设置。唯一的缺点是,如果要检查它是否已终止,或者评估返回代码,则需要将后台进程的pid恢复到当前shell。

答案 6 :(得分:1)

这也适用于killall(对于喜欢它的人):

killall -s SIGINT (yourprogram) 

抑制消息......我在后台模式下运行mpg123。 它只能通过发送ctrl-c(SIGINT)而不是SIGTERM(默认)来静默杀死。

答案 7 :(得分:1)

禁用作业通知的另一种方法是将命令置于sh -c 'cmd &'构造中。

#!/bin/bash
# ...
pid="`sh -c 'sleep 30 & echo ${!}' | head -1`"
kill "$pid"
# ...

# or put several cmds in sh -c '...' construct
sh -c '
sleep 30 &
pid="${!}"
sleep 5 
kill "${pid}"
'

答案 8 :(得分:0)

disown对我来说完全正确 - exec 3&gt;&amp; 2因为很多原因而存在风险 - set + bm似乎不能在脚本内部工作,只能在命令提示符

答案 9 :(得分:0)

在脚本中添加“jobs 2>&1 >/dev/null”是否成功,不确定它是否会帮助其他人的脚本,但这里有一个示例。

    while true; do echo $RANDOM; done | while read line
    do
    echo Random is $line the last jobid is $(jobs -lp)
    jobs 2>&1 >/dev/null
    sleep 3
    done

答案 10 :(得分:0)

简单:

{ kill $! } 2>/dev/null

优势?可以使用任何信号

例如:

{ kill -9 $PID } 2>/dev/null

答案 11 :(得分:0)

我发现将kill命令放在一个函数中,然后对该函数进行后台处理会抑制终止输出

function killCmd() {
    kill $1
}

killCmd $somePID &

答案 12 :(得分:0)

Terminated 由 bash 3.x 和 4.x 的默认信号处理程序记录。只需在子进程的第一个捕获 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 &
pid=$!

sleep 1 # wait trap is done

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

kill $pid ## no need to redirect stdin/stderr

sleep 1 # wait kill is done

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