I want to trap signal SIGTSTP, as simple as this:
trap "" SIGTSTP
However, pure shell (sh) does not support signal name, so a trap must use the signal number instead, like this:
trap "" 20
Problem: signal numbers are OS-dependent, so SIGTSTP in Linux is 20 but in AIX it's 18.
So to make it generic I decide to extract signal number from the result of trap -l. The raw input is:
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
I can't use grep, because the feature that I need, --only-matching, is not always supported. trap -l | grep -oE "[0-9]+\) SIGTSTP" | cut -d')' -f1 works well, but only in Linux.
I also failed to use sed because of the greedy problem described here
So trap -l | sed -nr 's/.*([0-9]+)\) SIGTSTP.*/\1/p' only returns 8, not 18
I want to make the extraction as generic as possible, so I won't assume SIGTSTP is a double-digit code, even when in reality it is.
Any suggestion?
To get a signal's number by its name in bash, ksh, or zsh, you can simply use:
kill -l TSTP # -> e.g., 18 - case doesn't matter, but do not use the "SIG" prefix
Since this uses the kill builtin (as opposed to the external-utility version, /bin/kill), this should work on any platform where these shells are supported.
Here's a POSIX-compliant solution that doesn't rely on a particular shell:
/bin/kill -l | tr -s '[:blank:]' '\n' |
awk -v name='TSTP' 'toupper($0) == toupper(name) {print NR}' # don't use "SIG" prefix
kill utility, /bin/kill, is used, with its -l option, for listing signals. While the POSIX spec for kill prescribes an output format, it doesn't mandate listing signals in a particular order. However, the order that makes sense is by their numerical value, and in practice that seems to be the case, and this approach relies on it./bin/kill - unlike the kill builtins in bash, ksh, zsh, and dash - does NOT report the signals SIGRTMIN through SIGRTMAX on Linux.As for the inverse operation - getting a signal name by its number - use kill -l <number>, e.g.:
kill -l 18 # -> e.g., 'TSTP'
The kill builtins in bash, ksh, zsh, and dash all support this.
The external /bin/kill implementations vary with respect to the syntax of the above:
macOS, GNU kill: the above form works.
procps-ng kill, as present on Ubuntu in 18.04 or below, for instance: only accepts
kill -l18 (or kill --list=18); that is, the option-argument must be directly attached to the -l option, which is the POSIX-compliant syntax, given that the signal number is an optional option-argument (-l by itself lists all signal names); see the POSIX utility argument syntax.
Unfortunately, the other implementations listed above only support the - potentially ambiguous - -l 18 form.
The procps-ng version that comes with Ubuntu 19.10 (procps-ng 3.3.15) supports both forms (and also --list 18).Tip of the hat to jarno for his help.
Try constraining the match with a word boundary:
trap -l | sed -nr 's/.*\b([0-9]+)\) SIGTSTP.*/\1/p'
This tested correctly [for me] for the target string as well as SIGPIPE.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With