shell 在Bash中识别接收信号名称

3z6pesqy  于 2023-03-30  发布在  Shell
关注(0)|答案(5)|浏览(152)

当接收到信号时,我可以使用trap执行一些命令。例如:

trap 'echo hello world' 1 2

如果接收到任何指定的信号,则显示“hello world”。
但如何打印/识别接收到的信号名称?

btqmn9zl

btqmn9zl1#

(If如果你只需要一个信号的编号和名称,kill -l $SIGNAL_NUM打印信号的名称;你可以通过使用信号名称而不是数字来避免这种情况,如下所示。
This answer表示无法访问信号名称,但如果您对捕获的每个信号都有一个单独的函数,那么您已经知道信号名称:

trap 'echo trapped the HUP signal' HUP
trap 'echo different trap for the INT signal' INT

在许多情况下,这可能就足够了,但是another answer on that same question使用这个事实来提供一个解决方案来伪造你想要的行为。它接受一个函数和一个信号列表,并为每个信号设置一个单独的陷阱,在用信号名称调用的函数上,所以在内部它实际上是一个单独的函数,每个信号都是一个单独的函数,但它看起来像是一个单一的陷阱,在一个单一的函数上获得信号名称作为参数:
验证码:

#!/bin/bash

trap_with_arg() {
    func="$1" ; shift
    for sig ; do
        trap "$func $sig" "$sig"
    done
}

func_trap() {
    echo "Trapped: $1"
}

trap_with_arg func_trap INT TERM EXIT

echo "Send signals to PID $$ and type [enter] when done."
read # Wait so the script doesn't exit.

如果我运行它,我就可以向进程发送信号,得到如下输出

Trapped: INT
Trapped: TERM
Trapped: EXIT
abithluo

abithluo2#

在trap中(通过信号触发时),$?变量最初设置为信号号加128,因此可以通过将trap操作的第一条语句设置为如下内容来将信号号分配给变量

sig=$(($? - 128))

然后可以使用kill命令获取信号的名称

kill -l $sig

更新:正如在评论中提到的,这对一些内置的shell命令不起作用。

(read)

而不是

read
mkshixfv

mkshixfv3#

for s in {1..64}; do trap "echo trap $s" $s; done

或者不害羞

s=1; while [ $s -le 64 ]; do trap "echo trap $s" $s; s=$((s+1)); done

设置64个单独的陷阱,每个陷阱对应一个可能的信号。
还有一个“signal”0没有包含在上面,因为它不是一个真正的信号。没有其他进程可以将它发送到您的进程。它实际上是一个钩子,只是使用信号/陷阱接口作为您安装钩子的方式。它捕获的是一个事件而不是信号,事件是退出。
trap "do stuff" 0
“do stuff”在shell退出时执行。
你可以使用{0..64}或s=0来包含它。
我不认为它对这个问题有用,因为它不是一个你需要检测的信号,比如“我刚刚收到了什么信号?”
你总是会在shell退出之前得到一个。
但您可能希望它检测到它没有运行,这是检测KILL的一种方法。
9包含在上面的1-64中,但是这个特定的陷阱永远不会实际执行,因为KILL会立即杀死,并且进程根本没有机会做任何其他事情,包括运行任何信号处理程序代码,为9或0或其他任何东西。
因此,如果你在0上有一个陷阱,它没有运行,这告诉你shell收到了一个KILL。(或者陷阱0的代码被破坏了,它不能告诉你它运行了,或者电源线被拉了,或者脚本仍在运行,等等。)
我在几乎每一个脚本上都使用它来进行最可靠和最方便的临时文件清理。不管脚本是否正常运行,或者它是否在中间的任何地方发生了错误,trap 0代码总是在退出前最后一件事。

atmip9wb

atmip9wb4#

参考上面的$?解决方案:$?将反映最后执行的命令的退出代码。请考虑以下情况:

#!/bin/bash
trap 'echo CODE: $?; exit 1' 1 2 3 15
sleep 3600

如果你运行这个程序并按下 Ctrl-C,它将打印CODE: 130。这是因为sleep可执行文件被SIGINT中断,并退出该代码。
比较一下:

#!/bin/bash
trap 'echo CODE: $?; exit 1' 1 2 3 15
read X

如果你运行这个命令并按下 Ctrl-C,它将打印CODE: 0,大概是因为read命令是内置的,退出代码规则是不同的(如果你中断while : ; do : ; done,也会发生同样的情况)。
所以,$?只在它中断了一个外部命令时告诉你信号,* 和 * 如果那个特定的程序没有捕捉到信号并用自己的退出代码退出。点的情况是上面的bash脚本:在收到SIGINT后,它将以代码1退出,而不是130

zdwk9cvp

zdwk9cvp5#

一个简单的方法来做到这一点:

_handler() {
   signal=$1
   echo signal was $signal
 }

 trap '_handler SIGTERM' SIGTERM
 trap '_handler SIGINT'  SIGINT

相关问题