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