mee*_*tar 17 bash kill signals shell-script
[编辑:这看起来类似于其他一些询问如何杀死所有产生的进程的问题——答案似乎都是使用 pkill。所以我的问题的核心可能是:有没有办法将 Ctrl-C/Z 传播到脚本产生的所有进程?]
当rec
使用timeout
来自 coreutils的命令(在此处讨论)调用 SoX 时,一旦从 Bash 脚本中调用它,似乎没有任何方法可以通过击键杀死它。
例子:
timeout 10 rec test.wav
Run Code Online (Sandbox Code Playgroud)
...可以用Ctrl+C或Ctrl+Z从 bash杀死,但不能从脚本内部调用它。
timeout 10 ping nowhere
Run Code Online (Sandbox Code Playgroud)
...可以被杀死Ctrl+C或Ctrl+Z从庆典,并与Ctrl+Z当它在脚本中运行。
我可以找到进程 ID 并以这种方式杀死它,但为什么我不能使用标准的中断键击?有什么方法可以构建我的脚本以便我可以吗?
Gil*_*il' 25
信号键如Ctrl+C向前台进程组中的所有进程发送信号。
在典型情况下,进程组是一个管道。比如在 中head <somefile | sort
,正在运行的进程head
和正在运行的进程sort
在同一个进程组中,shell也是,所以都接收到信号。当您在后台运行作业 ( somecommand &
) 时,该作业位于其自己的进程组中,因此按Ctrl+C不会影响它。
该timeout
程序将自己置于自己的进程组中。从源代码:
/* Ensure we're in our own group so all subprocesses can be killed.
Note we don't just put the child in a separate group as
then we would need to worry about foreground and background groups
and propagating signals between them. */
setpgid (0, 0);
Run Code Online (Sandbox Code Playgroud)
当超时发生时,timeout
通过杀死它所属的进程组的简单权宜之计。由于它已将自己置于单独的进程组中,因此其父进程将不在该组中。在这里使用进程组可以确保如果子应用程序分叉到多个进程中,它的所有进程都会收到信号。
当您timeout
直接在命令行上运行并按Ctrl+ 时C,timeout
子进程和子进程都会收到结果 SIGINT ,但它timeout
的父进程的交互式 shell 不会收到结果 SIGINT 。当timeout
从脚本调用时,只有运行脚本的 shell 会收到信号:timeout
因为它在不同的进程组中,所以不会收到信号。
您可以使用trap
内置命令在 shell 脚本中设置信号处理程序。不幸的是,事情并没有那么简单。考虑一下:
#!/bin/sh
trap 'echo Interrupted at $(date)' INT
date
timeout 5 sleep 10
date
Run Code Online (Sandbox Code Playgroud)
如果您在 2 秒后按Ctrl+ C,这仍会等待整整 5 秒,然后打印“中断”消息。这是因为当前台作业处于活动状态时,shell 会避免运行陷阱代码。
要解决此问题,请在后台运行该作业。在信号处理程序中,调用kill
将信号中继到timeout
进程组。
#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid
Run Code Online (Sandbox Code Playgroud)
小智 22
以 Gilles 提供的出色答案为基础。timeout 命令有一个前台选项,如果使用,则 CTRL+C 将退出 timeout 命令。
#!/bin/sh
trap 'echo caught interrupt and exiting;exit' INT
date
timeout --foreground 5 sleep 10
date
Run Code Online (Sandbox Code Playgroud)