Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Identifying received signal name in Bash

Tags:

linux

bash

shell

When a signal is received, I can execute some commands using trap. Example:

trap 'echo hello world' 1 2 

If any of the signals specified is received, the hello world' is displayed.

But how can I print/identify the received signal name?

like image 365
Lunar Mushrooms Avatar asked Feb 13 '12 06:02

Lunar Mushrooms


People also ask

What does #$ mean in bash?

#$ does "nothing", as # is starting comment and everything behind it on the same line is ignored (with the notable exception of the "shebang"). $# prints the number of arguments passed to a shell script (like $* prints all arguments). Follow this answer to receive notifications.

How does bash handle signals?

Bash installs signal handler for subcommands executed in bash scripts. This may not be the desired behavior for a low level signal handling C program, so do not rely on a signal handler being the default one, but always set it to the default signal handler explicitly.


2 Answers

(If you only have the number of a signal and want the name, kill -l $SIGNAL_NUM prints the name of a signal; you can avoid that by using the signal names instead of numbers in your call to trap as below.)

This answer says that there's no way to access the signal name, but if you have a separate function for each signal that you trap, then you already know the signal name:

trap 'echo trapped the HUP signal' HUP trap 'echo different trap for the INT signal' INT 

In many cases, that may be sufficient, but another answer on that same question uses that fact to provide a workaround to fake the behavior you want. It takes a function and a list of signals and sets a separate trap for each signal on that function called with the signal name, so internally it's actually a separate function for each signal but it looks like a single trap on a single function that gets the signal name as an argument:

Code:

#!/bin/bash  trap_with_arg() {     func="$1" ; shift     for sig ; do         trap "$func $sig" "$sig"     done }  func_trap() {     echo "Trapped: $1" }  trap_with_arg func_trap INT TERM EXIT  echo "Send signals to PID $$ and type [enter] when done." read # Wait so the script doesn't exit. 

If I run that, then I can send signals to the process and I get output like

Trapped: INT Trapped: TERM Trapped: EXIT 
like image 63
perelman Avatar answered Oct 12 '22 01:10

perelman


Within the trap (when triggered via a signal), the $? variable is initially set to the signal number plus 128, so you can assign the signal number to a variable by making the first statement of the trap action to something like

sig=$(($? - 128)) 

You can then get the name of the signal using the kill command

kill -l $sig 

Update: As noted in the comments, this doesn't work for some builtin shell commands. To have these set the trap's $? variable, they can be run in a subshell, Eg

(read) 

instead of

read 
like image 34
Phil Avatar answered Oct 12 '22 02:10

Phil