traps and shells

UNIX has signals, various signals. When you’re working on shell scripts, you may need to intercept and deal with them. The syntax for intercepting signals is the trap action SIG1 … SIGN, where depending on your shell the SIG1…SIGN may be specified as an integer (bourne shell, i.e. raw sh), or symbolically as HUP, TERM (ksh, bash, zsh). Of course those of you using csh and tcsh should get a real shell 🙂.


The default signal disposition of a process can be determined using the psig command under Solaris. on a typical shell, you can issue a psig $$, and it will tell you if the signal is blocked, if it is handled, if it is ignored, etc. some example output follows:

18489:  zsh
HUP     caught  zhandler        0
INT     blocked,caught  zhandler        0
QUIT    blocked,ignored
ILL     blocked,default
TRAP    blocked,default
ABRT    blocked,default
EMT     blocked,default
FPE     blocked,default
KILL    default
BUS     blocked,default
SEGV    blocked,default
SYS     blocked,default
PIPE    blocked,default
ALRM    blocked,caught  zhandler        0
TERM    blocked,ignored
USR1    blocked,default
USR2    blocked,default
CLD     caught  zhandler        0
PWR     blocked,default
WINCH   blocked,caught  zhandler        0
URG     blocked,default
POLL    blocked,default
STOP    default
TSTP    blocked,ignored
CONT    blocked,default
TTIN    blocked,ignored
TTOU    blocked,ignored
VTALRM  blocked,default
PROF    blocked,default
XCPU    blocked,default
XFSZ    blocked,default
WAITING blocked,default
LWP     blocked,default
FREEZE  blocked,default
THAW    blocked,default
CANCEL  blocked,default
LOST    blocked,default
XRES    blocked,default
JVM1    blocked,default
JVM2    blocked,default
RTMIN   blocked,default
RTMIN+1 blocked,default
RTMIN+2 blocked,default
RTMIN+3 blocked,default
RTMAX-3 blocked,default
RTMAX-2 blocked,default
RTMAX-1 blocked,default
RTMAX   blocked,default

In solaris we even see the address of the handler, and if the symbolic name of a function can be resolved that is used. This is really handy for debugging purposes (!!!)
When you are running a process in a shell on a terminal, when you exit the shell it will send a HUP signal to any of the processes that it has under it’s control. This is annoying, as if you forget to launch a process under nohup, you’ll normally end up terminating the program when you exit from the parent shell, because you 9/10 times forget this minor fact.
However you can prevent this from happening by using the ‘disown’ command (bash, zsh); which works from within the shell that you’re using. An alternative in Solaris is the nohup -p command – this takes a process ID and providing you can attach to the process (usual security caveats), it blocks the HUP and QUIT signals from being received by the process specified.
But, you can bypass the need for both of these by setting the shell to ignore the signals itselt using trap. When you pass in an empty string as the handler, it causes the shell to ignore that signal if it’s received. so you can gain the equivalent of nohup using the syntax: trap ” HUP QUIT at the start of your script. If you want to stop the signal being ignored then you can use trap – HUP QUIT , which is neat (temporarily ignoring sugnals).
special signals: EXIT (0)
This signal can be hooked to perform cleanup at the end of a shell’s execution. trap cleanup EXIT HUP QUIT is a common entry found at the start of scripts, and there’s a function definition for cleanup somewhere in the process. There is one minor minor gotcha with the EXIT handler within actual ‘function foo’ definitions on posix shells (ksh, bash), it means that the code is invoked at the end of the function. This comes in handy as a ‘finally’ clause in a function, mind you most of the time it’s a mistake that people tend to miss.
trapped in the office, time to go home.