在 bash 脚本中终止进程后,如何抑制出现的Terminated
消息?
我试过set +bm
了,但这不起作用。
我知道另一种解决方案涉及调用exec 2> /dev/null
,但这可靠吗?如何重置它以便我可以继续看到 stderr?
为了使消息静音,您必须stderr
在消息生成时进行重定向。因为kill
命令发送一个信号并且不等待目标进程响应,所以重定向stderr
命令kill
对你没有好处。内置 bashwait
是专门为此目的而制作的。
这是一个非常简单的示例,可以杀死最近的后台命令。(在此处了解有关 $! 的更多信息。)
kill $!
wait $! 2>/dev/null
因为两者都kill
接受wait
多个 pid,所以您也可以进行批量杀戮。这是一个杀死所有后台进程(当然是当前进程/脚本)的示例。
kill $(jobs -rp)
wait $(jobs -rp) 2>/dev/null
简短的回答是你不能。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给出的答案
解决方案:使用 SIGINT(仅适用于非交互式 shell)
演示:
cat > silent.sh <<"EOF"
sleep 100 &
kill -INT $!
sleep 1
EOF
sh silent.sh
也许通过调用将进程与当前的 shell 进程分离disown
?
这就是我们都在寻找的吗?
不想要:
$ 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 的作业控制(参见 'help set')。因此,如果您在子 shell 中输入命令(如在括号中所做的那样),您将不会影响当前 shell 的作业控制设置。唯一的缺点是,如果要检查后台进程是否已终止或评估返回码,则需要将后台进程的 pid 返回到当前 shell。
这也适用于 killall(对于那些喜欢它的人):
killall -s SIGINT (yourprogram)
抑制消息...我在后台模式下运行 mpg123。它只能通过发送 ctrl-c (SIGINT) 而不是 SIGTERM (默认) 静默地被杀死。
由 bash 3.x 和 4.x的Terminated
默认信号处理程序记录。只需在子进程的第一个捕获 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]'
disown 为我做了完全正确的事—— exec 3>&2 有很多风险—— set +bm 似乎不能在脚本中工作,只能在命令提示符下工作
禁用作业通知的另一种方法是将您的命令放置在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}"
'
在脚本中添加 ' 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
简单的:
{ kill $! } 2>/dev/null
优势?可以使用任何信号
前任:
{ kill -9 $PID } 2>/dev/null
我发现将 kill 命令放在一个函数中,然后将该函数置于后台会抑制终止输出
function killCmd() {
kill $1
}
killCmd $somePID &