why does `timeout 2 timeout 1 bash` stuck
Here's another example of the same behavior:
strace timeout 1 bash
Even if you interrupt the strace, bash will continue running.
If we strace the bash process itself in the same time, we notice the following looping.
--- SIGTTIN {si_signo=SIGTTIN, si_code=SI_USER, si_pid=7162, si_uid=1000} --- rt_sigaction(SIGTTIN, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f097723a7e0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f097723a7e0}, 8) = 0 ioctl(255, TIOCGPGRP, [6412])
= 0 rt_sigaction(SIGTTIN, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f097723a7e0}, {sa_handler=SIG_IGN, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f097723a7e0}, 8) = 0 kill(0, SIGTTIN) = 0
Now, according to http://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html
Macro: int SIGTTIN
A process cannot read from the user’s terminal while it is running as a background job. When any process in a background job tries to read from the terminal, all of the processes in the job are sent a SIGTTIN signal. The default action for this signal is to stop the process. For more information about how this interacts with the terminal driver, see Access to the Terminal.
timeout 2 timeout --foreground 1 bash
works, because the inner timeout will allow it to work with the tty, although it is not run directly from the interactive shell.
man timeout
--foreground when not running timeout directly from a shell prompt, allow COMMAND to read from the TTY and get TTY signals; in this mode, children of COMMAND will not be timed out
We can chain as many timeouts as we want, as long as all but the one ran from the interactive shell are with the --foreground
option:
timeout 3 timeout --foreground 2 timeout --foreground 1 bash
Also check the SIGNALS
section in man bash
for more info on how bash reacts to the various signals in different cases.