When I use the trap
command in Bash, the previous trap
for the given signal is replaced.
Is there a way of making more than one trap
fire for the same signal?
How to Use trap in Bash. A typical scenario for using the trap command is catching the SIGINT signal. This signal is sent by the system when the user interrupts the execution of the script by pressing Ctrl+C. The following example script prints the word "Test" every second until the user interrupts it with Ctrl+C.
You can't catch SIGKILL (and SIGSTOP ), so enabling your custom handler for SIGKILL is moot. You can catch all other signals, so perhaps try to make a design around those. be default pkill will send SIGTERM , not SIGKILL , which obviously can be caught.
$! is the process ID of the last job run in the background. $$ is the process ID of the script itself. (Both of the above are links to the Advanced Bash Scripting Guide on TDLP.)
Trap allows you to catch signals and execute code when they occur. Signals are asynchronous notifications that are sent to your script when certain events occur. Most of these notifications are for events that you hope never happen, such as an invalid memory access or a bad system call.
Technically you can't set multiple traps for the same signal, but you can add to an existing trap:
trap -p
Here is a bash function that does the above:
# note: printf is used instead of echo to avoid backslash # processing and to properly handle values that begin with a '-'. log() { printf '%s\n' "$*"; } error() { log "ERROR: $*" >&2; } fatal() { error "$@"; exit 1; } # appends a command to a trap # # - 1st arg: code to add # - remaining args: names of traps to modify # trap_add() { trap_add_cmd=$1; shift || fatal "${FUNCNAME} usage error" for trap_add_name in "$@"; do trap -- "$( # helper fn to get existing trap command from output # of trap -p extract_trap_cmd() { printf '%s\n' "$3"; } # print existing trap command with newline eval "extract_trap_cmd $(trap -p "${trap_add_name}")" # print the new trap command printf '%s\n' "${trap_add_cmd}" )" "${trap_add_name}" \ || fatal "unable to add to trap ${trap_add_name}" done } # set the trace attribute for the above function. this is # required to modify DEBUG or RETURN traps because functions don't # inherit them unless the trace attribute is set declare -f -t trap_add
Example usage:
trap_add 'echo "in trap DEBUG"' DEBUG
Edit:
It appears that I misread the question. The answer is simple:
handler1 () { do_something; } handler2 () { do_something_else; } handler3 () { handler1; handler2; } trap handler3 SIGNAL1 SIGNAL2 ...
Original:
Just list multiple signals at the end of the command:
trap function-name SIGNAL1 SIGNAL2 SIGNAL3 ...
You can find the function associated with a particular signal using trap -p
:
trap -p SIGINT
Note that it lists each signal separately even if they're handled by the same function.
You can add an additional signal given a known one by doing this:
eval "$(trap -p SIGUSR1) SIGUSR2"
This works even if there are other additional signals being processed by the same function. In other words, let's say a function was already handling three signals - you could add two more just by referring to one existing one and appending two more (where only one is shown above just inside the closing quotes).
If you're using Bash >= 3.2, you can do something like this to extract the function given a signal. Note that it's not completely robust because other single quotes could appear.
[[ $(trap -p SIGUSR1) =~ trap\ --\ \'([^\047]*)\'.* ]] function_name=${BASH_REMATCH[1]}
Then you could rebuild your trap command from scratch if you needed to using the function name, etc.
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