0

Please correct me if I am wrong: When a bash shell runs an external executable program, the bash shell will create a child process to run the program in foreground. If there is any key-generated signal, the signal will be sent to the child process and handled by program.

When a bash shell runs a builtin command, the bash shell will run the builtin command in the shell process directly in foreground. If there is any key-generated signal, will the signal be sent to the shell process? Which will handle the signal, the builtin command's program or bash? Can a builtin command have its own signal handler, or does it have to rely on the signal handlers of bash?

For example, when a bash shell is running wait in foreground and I press Ctrl-C, will the signal SIGINT be received by the shell process and handled by wait or by bash? Does wait have its own signal handler or rely on the signal handler of bash?

Thanks.

1
  • 1
    Shell built-in commands are not separate programs, the shell just calls some subroutine to implement what the built-in command is supposed to do. They are part of the shell, and signals are sent to the shell, since there is no other process. Aug 18, 2017 at 18:07

2 Answers 2

4

Which will handle the signal, the builtin command's program or bash?

The builtin command's program is bash. That's the definition of a builtin: it's built into the shell, it isn't an external program.

The shell might react differently depending on what it's doing when it receives a signal. But it's always the shell process that receives the signal, since there's no other process involved.

3

The easiest way to understand Linux terminal devices (/dev/tty*, /dev/pts/*) is if you think of them as streaming sockets. As if the /dev/tty12 would be a TCP port, like 127.0.0.1:8080.

Processes are connecting to them, get input from them, write into them, and then finally disconnect from them. A socket (terminal) can have a connection with multiple processes.

Other processes can listen on them, they are typically the terminal emulator programs, but not always. In the case of the character terminals, the Linux kernel itself works as a "listener daemon" on the terminal device.

The "extra feature" that a terminal has, but a socket hasn't: the kernel keeps track of which processes are connected to it, and it is capable to signal them on need. It so happens if, for example, you press Ctrl+c.

You can read a detailed list of the signals passed there answer.

What exactly happens if you press Ctrl+c?

It is not as if somebody presses a normal button, for example, an a key. In this case, the pressed key is simply written into the terminal device and can be read out by the processes reading from it (which is typically the process in the foreground).

In the case of special keypresses, for example, Ctrl+z, or when you close/resize the terminal window, and so on, the terminal gets the request and the kernel sends to all processes attached to it the corresponding signal. To all of them, it will be later important later.

These devices can be also controlled by well-directed ioctl() calls.

If bash runs a subprocess (i.e. external command), then the following happens:

  1. bash starts the process in the background, giving to it the terminal
  2. bash stops getting input from the terminal
  3. after the process stops, bash sets everything back.

However, the bash still remains attached to the terminal device, and if a Ctrl+c is coming, it will get the signal. Also the external command will get the signal.

However, these signals can be overridden (signal(), sigaction() system calls). Bash overrides them, i.e. it overrides the default signal handling routine (which would simply stop it) with its own. This is why it doesn't exit if you press the Ctrl+c in a command prompt.

However, a sleep 60 will exit. It doesn't change its signal handlers.

If you run a bash internal command, this signal handler will work as you said (it stops the internal command execution and gets you back to the prompt).

3
  • I disagree, in a way, with the last statement "If you run a bash internal command, this signal handler will work as you said (it stops the internal command execution and gets you back to the prompt)". This is up to the shell's implementation to stop (or not) the internal command when a catchable signal is received. It is not an "absolute rule" per se.
    – Totor
    Nov 4, 2021 at 21:44
  • @Totor Ok I think you are refering some standard (probably some posix thing), I referred here bash. Honestly I can not really believe in posix any more, since I do not really see any non-Linux posix implementation on the market. The answer was created in the assumption that we have Linux and its common environment (incl. bash). But I agree your point, feel free to edit the post (but please beware the context).
    – peterh
    Nov 4, 2021 at 22:14
  • Well, if you say that you saw somewhere (documentation, source code, tests, etc.) that every bash internal command (POSIX or not) is going to be interrupted by a Ctrl+C/TERM signal, then this statement is true. So did you?
    – Totor
    Nov 5, 2021 at 2:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.