Linux Bash – Terminal Emulator SIGHUP Trap Issue

bashlinuxsighupsignalsterminal-emulator

In a bash shell in a terminal emulator window of lxterminal, I run

$ trap "echo hello" SIGHUP 
$ kill -s HUP $$
hello
$

and then I close the terminal emulator window.

Does closing the terminal emulator window only cause SIGHUP sent to the controlling process i.e. the bash process?

Since the SIGHUP trap doesn't terminate the bash process, I expect the bash process isn't terminated, but why is the bash process actually terminated?

Same thing happen if I change the trap to "" (ignore).

Terminal emulator matters. In bash running in a xterm window, setting trap to "" will make a xterm window not closable, while setting trap to echo hello can still close a xterm window.

Thanks.

Best Answer

[ I'll ignore the actual and possible behavior of different terminal emulators; a completely reasonable behavior would be to send a ^D (VEOF) to the pty on a window close / WM_DELETE_WINDOW, instead of tearing it down and causing the process running in it to receive a SIGHUP; the following assumes xterm, which will send a SIGHUP to the shell's process group in that case ].

The behavior you're seeing is because of the readline library, which is installing its own signal handlers. If you try the following:

xterm -e bash --noediting

(or dash, zsh or ksh instead of bash --noediting), then run

trap 'echo HUP' HUP

in the terminal, the window will become unclose-able; the shell will just print HUP as expected on trying to close the window; forcefully closing it (eg. with xkill) will cause the shell to exit with EIO errors, which is completely expected, since the pty was torn down.

Here is a simpler testcase for the behavior you're observing, not involving terminal emulators. Run the following in your terminal:

bash --rcfile <(echo 'trap "echo HUP" HUP')

Then kill -HUP $$ will just print HUP, but (sleep 1; kill -HUP $$) & (or kill -HUP <pid> from another window) will cause the shell to print exit and exit, unless you started it with --noediting (= don't use readline)

The readline() function as called by bash will install its own signal handlers upon waiting for input from the user, and restore the original handlers upon returning; a SIGHUP while waiting for input from the user will cause it to return NULL, which will be treated as EOF by bash (in the yy_readline_get() function), before having the chance to run the deferred trap handler.

Related Question