Trap: A Shell built-in Command
You might have come across a few shell scripts on the Internet, which are used in production, that use a keyword called trap
. Naturally, you are wondering what the heck is this trap
keyword, how is it useful and how do I use it in my scripts?
All of these questions will be answered in this article :)
What is the trap command?
When you use a command like ls
or cd
, they are provided by a third-party utility/package. In this case, the ls
and cd
commands are provided by the GNU Coreutils package.
But, when you create a Shell script, you will be using keywords like if
, else
, elif
, fi
and more. These are not some binaries living inside /usr/bin
. They are the commands that are part of the POSIX-compliant shell that you are using.
Similar to the if
, else
and other keywords, there is the trap
command built-in. This trap
built-in is used to trap (catch) any supported signals and react upon it.
The list of supported signals can be checked by running the trap -l
command.
Following is the output from my computer:
$ trap -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
Meaning, if you do a
kill -9 PID
, you are sending the SIGKILL
signal to said PID.Though, it is largely recommended to use these signals because it makes the code easier to read ;)
When the trap
built-in is used, it will listen for signals that it supports. If the trap
built-in is told to check for a signal, when that signal is received by the script, trap
will execute the action you mentioned.
Using the trap command
The best practice is practicals. No one said this; I just came up with it. But still pretty accurate, wouldn't you agree?
But first, let me bore you just a bit with the syntax:
trap ACTIONS SIGNALS
Here, substitute SIGNALS
with one or more signals that you want to monitor within the script. Once the trap
built-in catches even one of the mentioned signals, any ACTIONS
(it is usually a function call) that you provide will be performed.
Listening for supported signals
The easiest way to use trap
is for a clean-up of sorts. Let's say that you are running a task in one of the shell scripts.
As the script is running, a user presses the Ctrl + C
key combination. How would you clean-up the artifacts now? Simple, use the trap
built-in.
Let me demonstrate this with a simple Bash script. Its contents are as the following:
#!/usr/bin/env bash
function sig_int() {
echo "The sleep was disturbed by Jarasandha"
}
trap sig_int SIGINT
sleep 10m
There is a function called sig_int
which, when called will echo the string "The sleep was disturbed by Jarasandha". Under that, there is the use of the trap
built-in. It is listening for the SIGINT signal and upon receiving it, it will call the sig_int
function.
Let's try this!
$ ./trap-script.sh
^CThe sleep was disturbed by Jarasandha
As soon as I pressed the Ctrl + C
key (as evident by ^C
), the echo
statement inside the body of the sig_int
function was called.
Sending other signals
SIGINT
is not the only signal that you might want to monitor for. Therefore, you may want to verify whether your script is correctly listening for intended signals. In that case, you can send a signal externally using the kill
command.
Following is the syntax for this particular use:
kill -s SIGNAL PID
As it might be obvious now, use the -s
option to specify which signal you intend to send. Then, specify the PID of the program to which you want to send the signal.
I will make a slight modification to the way I execute this script... I will run it in the background so I can use the same shell to run the kill
command to send the signal.
$ ./trap-script.sh &
[1] 28550
$ kill -s SIGINT 28551
$ The sleep was disturbed by Jarasandha
[1] + exit 130 ./trap-script.sh
Look closely. The PID of the script that was put in the background is 28550
but I am sending SIGINT
to the shell script's PID + 1 PID (28551
). The reason is that the active process is the sleep command which is running inside our bash script ;)
You are actually monitoring the signals for the commands running inside the script. Not the script itself.
Conclusion
The trap
is a bash built-in that is used to monitor for signals that are usually received by your shell script.
This article practically demonstrates how to listen for supported signals with the example of the SIGINT
signal. We also look at how to send a signal using the kill
utility.
Of course, there are many more built-ins you can explore.
Let me know if you have questions.