通过信号名称查找信号编号

Yuk*_*awa 4 linux shell aix signals sed

我想捕获 signal SIGTSTP,就像这样简单:

trap "" SIGTSTP
Run Code Online (Sandbox Code Playgroud)

然而,纯 shell ( sh) 不支持信号名称,因此陷阱必须使用信号编号来代替,如下所示:

trap "" 20
Run Code Online (Sandbox Code Playgroud)

问题:信号编号取决于操作系统,因此 Linux 中的 SIGTSTP 为 20,但在 AIX 中为 18。

因此,为了使其通用,我决定从 的结果中提取信号编号trap -l。原始输入是:

 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGABRT      7) SIGEMT       8) SIGFPE
 9) SIGKILL     10) SIGBUS      11) SIGSEGV     12) SIGSYS
13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGURG
17) SIGSTOP     18) SIGTSTP     19) SIGCONT     20) SIGCHLD
21) SIGTTIN     22) SIGTTOU     23) SIGIO       24) SIGXCPU
25) SIGXFSZ     27) SIGMSG      28) SIGWINCH    29) SIGPWR
30) SIGUSR1     31) SIGUSR2     32) SIGPROF     33) SIGDANGER
34) SIGVTALRM   35) SIGMIGRATE  36) SIGPRE      37) SIGVIRT
38) SIGALRM1    39) SIGWAITING  50) SIGRTMIN    51) SIGRTMIN+1
52) SIGRTMIN+2  53) SIGRTMIN+3  54) SIGRTMAX-3  55) SIGRTMAX-2
56) SIGRTMAX-1  57) SIGRTMAX    60) SIGKAP      61) SIGRETRACT
62) SIGSOUND    63) SIGSAK   
Run Code Online (Sandbox Code Playgroud)

我无法使用grep,因为我需要的功能 ,--only-matching并不总是受支持。trap -l | grep -oE "[0-9]+\) SIGTSTP" | cut -d')' -f1运行良好,但仅限于 Linux。

sed由于这里描述的贪婪问题,我也未能使用

所以trap -l | sed -nr 's/.*([0-9]+)\) SIGTSTP.*/\1/p'只返回8,不返回18

我想让提取尽可能通用,所以我不会假设SIGTSTP它是两位数代码,即使实际上它是。

有什么建议吗?

mkl*_*nt0 5

要通过的名称获取信号编号,您可以简单地使用:bashkshzsh

kill -l TSTP # -> e.g., 18 - case doesn't matter, but do not use the "SIG" prefix
Run Code Online (Sandbox Code Playgroud)

由于它使用kill 内置的(而不是外部实用程序版本/bin/kill),因此它应该适用于支持这些 shell 的任何平台


这是一个符合 POSIX 标准的解决方案,不依赖于特定的 shell:

/bin/kill -l | tr -s '[:blank:]' '\n' | 
  awk -v name='TSTP' 'toupper($0) == toupper(name) {print NR}' # don't use "SIG" prefix
Run Code Online (Sandbox Code Playgroud)
  • 外部 kill实用程序及其/bin/kill选项用于-l列出信号。虽然POSIX 规范kill规定了输出格式,但它并不强制要求按特定顺序列出信号。然而,有意义的顺序是按它们的数值排列的,在实践中似乎就是这种情况,并且这种方法依赖于它。
  • 需要注意的是/bin/kill,与 bash、ksh、zsh 和 dash 中的内置函数不同,它不会在 Linux上kill报告信号。SIGRTMINSIGRTMAX

至于运算 -通过信号编号获取信号名称- 使用kill -l <number>,例如:

 kill -l 18  # -> e.g., 'TSTP' 
Run Code Online (Sandbox Code Playgroud)

、、和kill中的内置函数都支持这一点。bashkshzshdash

外部/bin/kill实现因上述语法而异:

  • macOS、GNU kill:以上形式有效。

  • procps-ng ,如 Ubuntu 18.04 或更低kill版本中所示,例如:仅接受(或);也就是说,选项参数必须直接附加到选项上,这是符合 POSIX 的语法,假设信号号是可选的选项参数(其本身列出了所有信号名称);请参阅POSIX 实用程序参数语法
    kill -l18kill --list=18-l-l

不幸的是,上面列出的其他实现支持(可能不明确的)-l 18形式。

Ubuntu 19.10附带的 procps-ng 版本(procps-ng 3.3.15)支持这两种形式(也支持--list 18)。向亚诺的帮助致敬。