按信号名称查找信号编号

时间:2015-03-31 20:31:21

标签: linux shell sed signals aix

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

trap "" SIGTSTP

但是,纯shell(sh)不支持信号名称,因此陷阱必须使用信号编号,如下所示:

trap "" 20

问题:信号编号与操作系统有关,因此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   

我无法使用grep,因为我并不总是支持我需要的功能--only-matchingtrap -l | grep -oE "[0-9]+\) SIGTSTP" | cut -d')' -f1效果很好,但只适用于Linux。

由于所描述的贪婪问题here

,我也未能使用sed

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

我想尽可能使提取成为通用的,所以我不认为SIGTSTP是一个两位数的代码,即使它实际上是。

有什么建议吗?

4 个答案:

答案 0 :(得分:2)

尝试使用单词边界约束匹配:

trap -l | sed -nr 's/.*\b([0-9]+)\) SIGTSTP.*/\1/p'

这对于目标字符串以及SIGPIPE正确地测试[对我来说。

答案 1 :(得分:2)

bashkshzsh 按名称获取信号号码,您只需使用:

kill -l TSTP # -> e.g., 18 - case doesn't matter, but do not use the "SIG" prefix

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


这是一个不依赖于特定shell的 POSIX兼容解决方案

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

对于操作 - 通过 获取信号名称 - 使用{{1} },例如:

kill -l <number>

kill -l 18 # -> e.g., 'TSTP' killbashksh中的zsh内置版都支持此功能,而dash 应该支持根据POSIX支持此功能,并非所有实现都支持(例如,在Ubuntu 14.04上找到的/bin/kill版本。)

答案 2 :(得分:1)

试试这个:

trap -l | sed  -nr 's/^([^0-9]*|.*[ \t])([0-9]+)\) SIGURG.*$/\2/p'

现在一切都正常运行。

加埃塔诺

答案 3 :(得分:1)

更新:我找到了much simpler solution对于sed版本与编写可移植sed命令之间的差异,某些人可能仍会对此答案感兴趣。


accepted answer在以下情况下运作良好:

  • 支持sed支持扩展正则表达式的-r实现可用。
  • bash用于执行命令,因为sed命令需要 bash trap 内置的输出格式使用-l选项生成。
  • 平台的正则表达式库支持\b进行字边界断言。

这适用于OP,但并非所有平台都满足这些要求,特别是类似BSD的平台,包括OSX。

警告:

  • 如果您指定(a)完整的信号名称(例如,SIGUSR1与仅SIGUSR),则接受的解决方案只能明确地工作,这是(b)不是另一个信号名称的子字符串(例如,SIGRTMAXSIGRTMAX-1)。

鉴于扩展正则表达式的功能,在sed -r支持\b的平台上解决这个缺点并不难(这是修正的(非便携式)已接受解决方案的版本):

trap -l | sed -nr 's/.*\b([0-9]+)\) SIGTSTP(\s.*|$)/\1/p'

注意最后的交替...|...),其中规定信号名称后跟空格或行尾。
(请注意,同样使用\b not 一般都会工作,因为它会在-之前匹配, 是某些信号名称的有效部分)。

这里是(也是非便携式)等效的BSD类似平台的修正接受答案,包括OSX

trap -l | sed -nE 's/.*[[:<:]]([0-9]+)\) SIGTSTP([[:blank:]].*|$)/\1/p'

请注意,虽然-E也启用扩展正则表达式,但支持的特定风格与Linux版本不同:必须使用[[:<:]]代替\b[[:blank:]]代替\s

可悲的是,POSIX BREs (basic regular expressions)的限制不允许更改,并且使用sed可以将一个限制为BRE。 因此,无法使用符合POSIX标准的BRE 直接模拟修正命令中的 扩展正则表达式。 (请注意, GNU sed 支持支持BRE中的更改,但这是一个不合规的扩展。)< / p>

这是强大,可移植的解决方案可以在任何与bash 相关的POSIX兼容平台上运行;它使用了一种解决方法,因为它无法使用正则表达式替换:

trap -l |
 sed -n 's/^/ /; s/$/ /; s/.*[[:blank:]]\([0-9]\{1,\}\)) SIGTSTP[[:blank:]].*/\1/p'
  • s/^/ /; s/$/ /只需在每一行前面添加一个空格字符,以便保证每个信号编号和信号名称都用空格分隔,这样可以简化匹配。
  • 请注意,由于必须使用基本正则表达式,特殊字符。例如({需要转义
  • POSIX char。必须使用[[:blank:]]等类来代替\s等快捷方式。
  • 必须使用+模拟复制符号\{1,\}

但请注意,该解决方案本身并不符合POSIX:

  • trapbash中的内置,因此其trap -l输出格式与所有相同 < / em>运行bash的平台 - 但请注意bash本身,而POSIX- 兼容,并非POSIX本身强制实施,并实现了许多扩展< / em>到POSIX标准 - trap -l是其中之一 上述命令依赖于bash的{​​{1}}输出格式,如问题所示。

POSIX兼容性说明:

  • POSIX trap builtin不支持trap -l,而POSIX kill utility支持http://man.cx/kill,但它规定了不同的格式
    &#34;当指定-l选项时,每个信号的符号名称应采用以下格式编写:-l,其中"%s%c", <signal_name>, <separator>为大写,而不是{{ 1}}前缀,<signal_name>应为SIG<separator>。对于最后写入的信号,<newline>应为<space> - {{3}};
    例如:<separator> 该规范并未强制要求列出信号的 order ,但在实践中,实现似乎按数值的升序列出它们。

  • 但是,<newline>还有一个HUP INT QUIT ILL ... 内置,其bash选项会产生与相同的输出{ {1}}。 Builtins优先于实用程序,因此kill -l内置阴影外部trap -l实用程序。因此,bashkill(和kill)生成的输出偏离了POSIX规定的格式,如下所示:

    • 信号名称​​以数字为前缀,格式为kill -l,后跟空格
    • 信号名称​​ do 具有trap -l名称前缀。
  • 因此,bash&#39; <number>)输出符合NON-POSIX标准,除非您在POSIX模式下运行SIG(例如,通过运行{{1} }})。相比之下,bashkill -lbash DO中的shopt -so posix内置函数默认符合POSIX规定的输出格式