我想捕获信号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-matching
。 trap -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
是一个两位数的代码,即使它实际上是。
有什么建议吗?
答案 0 :(得分:2)
尝试使用单词边界约束匹配:
trap -l | sed -nr 's/.*\b([0-9]+)\) SIGTSTP.*/\1/p'
这对于目标字符串以及SIGPIPE正确地测试[对我来说。
答案 1 :(得分:2)
要 bash
,ksh
或zsh
按名称获取信号号码,您只需使用:
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上报告SIGRTMIN
到SIGRTMAX
的信号。 对于逆操作 - 通过号 获取信号名称 - 使用{{1} },例如:
kill -l <number>
kill -l 18 # -> e.g., 'TSTP'
,kill
,bash
和ksh
中的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。
警告:
SIGUSR1
与仅SIGUSR
),则接受的解决方案只能明确地工作,这是(b)不是另一个信号名称的子字符串(例如,SIGRTMAX
与SIGRTMAX-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)的限制不允许更改,并且使用 这是强大,可移植的解决方案,可以在任何与 但请注意,该解决方案本身并不符合POSIX: POSIX兼容性说明: POSIX 但是, 因此,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/$/ /
只需在每一行前面添加一个空格字符,以便保证每个信号编号和信号名称都用空格分隔,这样可以简化匹配。(
和{
需要转义。[[:blank:]]
等类来代替\s
等快捷方式。+
模拟复制符号\{1,\}
。
trap
是bash
中的内置,因此其trap -l
输出格式与所有相同 < / em>运行bash
的平台 - 但请注意bash
本身,而POSIX- 兼容,并非POSIX本身强制实施,并实现了许多扩展< / em>到POSIX标准 - trap -l
是其中之一
上述命令依赖于bash
的{{1}}输出格式,如问题所示。
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
实用程序。因此,bash
中kill
(和kill
)生成的输出偏离了POSIX规定的格式,如下所示:
kill -l
,后跟空格trap -l
名称前缀。bash
&#39; <number>)
输出符合NON-POSIX标准,除非您在POSIX模式下运行SIG
(例如,通过运行{{1} }})。相比之下,bash
,kill -l
和bash
DO中的shopt -so posix
内置函数默认符合POSIX规定的输出格式 。