7

Does the terminal have its input routed through the bash process into the program currently being run, or is the terminal "disconnected" from the bash process and connected to the new program, preventing bash from intercepting or interfering?

Does bash just freeze in the background, waiting for the program you started to close, or is it doing stuff?

When I close a terminal window, am I sending a signal to bash, which in turn sends a signal to the foreground process closing both of them? Or am I sending a signal to the foreground process, which propagates upwards to bash?

1
  • 2
    Mostly it sits around twiddling its file descriptors.
    – muru
    Nov 14, 2019 at 2:30

3 Answers 3

4

Does the terminal have its input routed through the bash process into the program currently being run, or is the terminal "disconnected" from the bash process and connected to the new program, preventing bash from intercepting or interfering?

Neither. Assuming a simple foreground command with no pipes or redirects... Input from the user and output back to the user are not routed through bash. But bash is not prevented from interfering, bash simply does not try to interfere.

When a program opens any file or terminal it receives a file descriptor which it uses to read and write. The child inherits copies of the parent's set of open file descriptors.

When you type something at the terminal, it is passed to the process via it's stdin. When it writes something to the user it does to by writing to either the stdout or stderr. Stdin, stdout and stderr are all file descriptors with predictable IDs: by POSIX standard these are numbered 0 1 2 respectively. So when bash runs a program, it first creates the child process with fork and the child automatically inherits the same stdin, stdout and stderr FDs. So the child will automatically read from and write to the exact same terminal.

Note "running a program" is done by calling fork then execve. Pipes and redirects are achieved by replacing stdin, stdout and stderr by calling dup2 between fork and execve.

So the "program" can read directly from the same terminal as bash. This does not stop bash or anything else reading and writing to the same terminal. If bash actually tried to, it could cause a mess. Multiple processes writing results in everything being written in an unpredictable order. Multiple processes reading results in some bytes (key strokes) going to one process and some going to another.

Does bash just freeze in the background, waiting for the program you started to close, or is it doing stuff?

It effectively freezes. More accurately it waits. As far as I know it explicitly calls waitpid() or wait3() (depending on what Unix you run the shell on) which waits for the child to terminate.

When I close a terminal window, am I sending a signal to bash, which in turn sends a signal to the foreground process closing both of them? Or am I sending a signal to the foreground process, which propagates upwards to bash?

Sorry I can't remember this behavior off the top of my head. I believe closing the terminal [window] will usually kill the running process even if it does not read or write anything so I don't believe it's based on a terminal read causing an EOF. I believe closing the terminal causes a signal. I'll edit the answer if I find the right answer.

I do know that some children can effectively intercept keyboard interrupt key sequences preventing bash from receiving them. I'm not sure if that means they are intercepting the signal or just disabling the terminal from generating signals all together.

1
0

The question that hasn't been asked is: what happens when you start a process asynchronously (with & ) and why is that different to typing a command without the & ?

The important thing here is called "inheritance". When your interactive shell has nothing else to do, it sticks up your prompt (the PS1 variable) and puts a read up on its stdin. It hangs on this because the window manager has no keystrokes to write to the stream that it created to talk to shell when it was initiated.

If you type a command name, the shell will "fork" (replicate) itself, and the child inherits stdin, stdout, stderr from the shell. The child shell then tells the kernel to load the command over itself ("execve").

The catch is, the window manager now has two processes reading the same stream -- the original shell and the child command. What to do? Who gets to read the next thing you type?

For a synchronous "foreground" child, the child command ought to get the data. So the shell does not put up a read on stdin. Instead, it goes into a sleep, from which it expects to be awaken by a SIGCHLD when the child exits and its exit status is available. So there is no way to tell it to start a second foreground child,

For an asynchronous "background" child, the child is forked with stdin disconnected (connected to /dev/null). Stdout and stderr are still connected (unless they were redirected) so async processes can still send to the terminal (although line synchronisation may be random). The shell then puts up its prompt and waits for the next command (which might be "jobs", for example). It can start other async processes, or run one command at a time, or process built-in shell commands, so you can have many background jobs at once. It still gets a SIGCHLD when each async child exits, and it can go collect the status, remove it from the jobs list, and so on.

I suspect that, when you close the terminal, the shell gets EOF on the stream that it was getting window input from. It terminates all its children, using an internal list set up as it starts each one.

3
  • Window managers are an X thing, replace that with "the terminal" and this sounds about right to me. The sleep the shell goes to is the wait() system call (or one of the dozen or so variants of it).
    – ilkkachu
    Nov 13, 2019 at 22:13
  • @ilkkachu Not important, but it's waiting with either wait3() or waitpid() depending on Unix (the WAITPID macro in job.c).
    – Kusalananda
    Nov 13, 2019 at 22:28
  • 2
    A process run asynchronously (with &) is NOT redirected to /dev/null; it still has the tty open, but it is in a different process group so trying to read (and optionally write) the tty causes it to be suspended; you can use the shell fg command to give that pgrp (aka 'job') access and it can then use the tty just fine (unless you ^Z which takes the tty away again, back to the shell). See (long!) unix.stackexchange.com/a/509566/59699 Nov 14, 2019 at 5:19
-1

One important difference to understand is the distinction between Terminal and Shell. The terminal is the interface you use to type in your commands, read text and receive output from programs on your computer screen. The Shell on the other hand is the entity that is responsible for executing the program through interacting with the kernel.

Your terminal doesn't "hang". It doesn't display a new prompt at it is "waiting" for the shell to finish the process. You can use multiple terminals over the same machine (this is what tmux is capable of!).

When you enter a command on the terminal, or run a program, the terminal handles parsing your keystrokes and pass it to the shell which will then run the process by parsing your input. Once the input is passed to the shell, the terminal has done its job for now. All it does now it wait for the script to end.

This explanation should answer your last question as well. When you close the terminal screen, that signal is propagated to the program currently running to kill it.

1
  • This doesn't really answer the question. I think that the user knows the difference between a shell and a terminal. The question is whether the shell just waits for the spawned process (you say it just waits), and also what exactly terminates a process started from a shell when you close a terminal window, the shell or the terminal application, and what terminates the shell exactly (you don't answer this)? I would also throw in that sometimes a process started from a shell isn't killed. So you may want to address that as well.
    – Kusalananda
    Nov 13, 2019 at 21:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .