36

The terminal is running when we open it.

luvpreet@DHARI-Inspiron-3542:/$

I have just opened it. So, when I press Ctrl+C, why doesn't it kill itself and close the terminal??

46

Ctrl+C is the interrupt signal. When you type this in a terminal, bash sends SIGINT to the job in the foreground. If there is no job (which is the case when you've just opened a terminal), nothing happens. The terminal emulator program is not a job running in the shell, so, it doesn't get the signal and doesn't close.

If you want to close the terminal with a control key, use Ctrl+D (EOF) which causes bash to exit (and closes the terminal too).

See also: Bash Beginner's Guide on signals and in more depth How signal handling works
note: this answer has been edited since comments were posted

  • 4
    The proper term is that shell will "trap" the signal. Different story is when you launch a terminal window from within another window. Sending ctrl+c to parent window will kill the child process. – Sergiy Kolodyazhnyy Mar 7 '17 at 19:26
  • 1
    In addition, GUI windows can also be instructed to trap specific signals coming from X11 server. That is how you can have popups notifying you of unsaved work, or open tabs as in browsers – Sergiy Kolodyazhnyy Mar 7 '17 at 19:28
  • 8
    @chrylis the terminal program just sends the ctrl-c character, it's actually the kernel tty layer that turns it into the signal. – Random832 Mar 7 '17 at 19:48
  • 3
    @chrylis: And the terminal, or a program running inside it - for instance a text editor - may well translate Ctl-C to some other action. – jamesqf Mar 7 '17 at 19:51
  • 3
    I don't think bash will terminate any programs when ctrl-c is pressed. It will just tell the kernel which process group is active and the kernel will generate a signal to that process group when it receives ctrl-c from the terminal program. – kasperd Mar 7 '17 at 20:55
32

The ^C keystroke, like other keystrokes*, isn't magic--it sends a keycode to whichever program has focus. (In X, the keycode is 54 for the C with a modifier of 0x4 for Ctrl.) The program that's receiving the stream of keys is responsible for doing something appropriate with them--remember that in many GUI applications, the keystroke copies to the clipboard.

When a GUI terminal emulator (e.g., Konsole) or a virtual terminal receives a keystroke that it interprets as ^C, it can do one of three things. If the terminal is in raw mode, then the running program has asked the terminal not to perform any handling of special keys itself and to pass them straight to the program. Some programs that support advanced features like line editing receive keyboard input in some configuration in between complete raw keystrokes and processed lines of text; bash, for example, receives keystrokes one at a time. ^C is interpreted by the terminal, but the backspace key is sent to the shell as-is.

Most programs, however, use cooked mode (because it isn't raw), where the terminal interprets some basic keystrokes before actually sending them to the program (this is why you can use backspace in cat). In this mode, the terminal itself translates the ^C keystroke into a SIGINT signal and sends it to the child process. Since the terminal generated the signal, it will not get confused and terminate.

  • SysRq really is magic.
  • Obviously not super-relevant here, but for general computing there are more magic keystrokes out there. Most famously, Ctrl+Alt+Delete in the Windows world, where the key combination is pretty close to magic (it can be used to get Windows to work, that's pretty magical in and of itself!), since it's hard-coded into the system to interrupt and override pretty much everything—pretty similar to SysRq in that sense. – KRyan Mar 7 '17 at 19:45
  • 7
    Bash does not use raw mode - it uses character-at-a-time mode i.e. cbreak/-icanon, but it does leave the isig mode set, and does receive real signals when you press keys that are mapped to them. It handles SIGINT by behaving as you described (it doesn't just cancel line editing, it also cancels any internal command that may be running in a loop), and completely ignores SIGTSTP and SIGQUIT. Other programs, such as vi, may not. – Random832 Mar 7 '17 at 19:55
  • 1
    @KRyan Ctrl+Alt+Delete used to be even more magic than it is today - blogs.msdn.microsoft.com/oldnewthing/20140912-00/?p=44083 . Though I'm a Linux person at heart I'm often considerably awed by the extent Windows went to make things user-friendly and logical with such limited resources in the early days. – Muzer Mar 8 '17 at 10:25
  • On some OS's, even if another program has focus the system (window manager I guess?) actually gets the keypresses before the terminal emulator ever does. If you are able to configure keyboard shortcuts to snap windows, open applications, trigger scripts then before the keys pressed are sent to the terminal emulator they are checked for any shortcuts you have configured. And another example if you have no applications open ^c won't kill the window manager :). Not able to comment on raw/cooked character at a time stuff, but the answer is spot on about how that keystroke is generating SIGINT – Ajay Mar 8 '17 at 19:36
  • 2
    "cooked mode (because it isn't raw)": I'm... speechless. After all these years, I never made the connection. – isanae Mar 9 '17 at 7:50
8

^C is usually mapped (see stty -a) to the SIGINT signal (see man 7 signal).

An un-caught SIGINT interrupts the running process, BUT...

SIGINT is one of the signals that a process can specify behaviour for ("Catching a signal").

What you call "the terminal" catches SIGINT, and goes back to work.

7

When I was a beginner I was missing the part that when I was using the command line I actually was using two seperate programs, a terminal and a shell (e.g. bash)

The shell is what you already probably know, a program that takes as input commands or scripts, executes them and prints their output.

The terminal on the other side is like a man in the middle between the user and a program (which program is usually a shell like bash or fish). What the terminal does is to read the input for example from the keyboard, maybe process that input in some way, and redirect it to the other program (bash).

Also this works in the other way too, when the other program outputs something, that something is redirected to the terminal, then it's the terminal's job to output that something to the screen. In between getting input and printing it to the screen the terminal can interpret the input it is getting in various ways.

For example if a program outputs the following sequence:

\e[0;31m some extra foobar text

The terminal will output to the screen "some extra foobar text" with red colored letters. This is because the terminal chooses to treat that weird code in a special way which code hints it to print the following output in red.

Similarly when the user presses Ctrl - C, the only special thing about this is that the terminal chooses to treat it in a special way, there is nothing other special about this key sequence. Specifically this hints it to sent the interrupt signal (SIGINT) to the process that is running inside the terminal, that is the shell. If at that moment exists any program that has been spawned by the shell and is currently running in the foreground it also receives the signal. Now the shell has a special handler for this signal and nothing happens. But most programs have the default handlers which in SIGINT's case just exit.

5

Every signal has a default action associated with it. The default action for a signal is the action that a script or program performs when it receives a signal.

Ctrl+C sends the "interrupt" signal (SIGINT), which defaults to terminating the process to the job running in the foreground.

Ctrl+D tells the terminal that it should register a EOF on standard input, which bash interprets as a desire to exit.

A process can choose to ignore the INT signal, and Bash does so when it's running in interactive mode.

From the manual:

When bash is interactive, in the absence of any traps, it ignores SIGTERM (so that kill 0 does not kill an interactive shell), and SIGINT is caught and handled (so that the wait builtin is interruptible). In all cases, bash ignores SIGQUIT. If job control is in effect, bash ignores SIGTTIN, SIGTTOU, and SIGTSTP.


Understand it with trap:

trap is a function built into the shell that responds to hardware signals and other events. It defines and activates handlers to be run when the shell receives signals or other special conditions.

trap [-lp] [arg] [sigspec …]

-l print a list of signal names and their corresponding numbers.
-p display the trap commands associated with each SIGNAL_SPEC.

arg are to be read and executed when the shell receives signal sigspec. Each sigspec is either a signal name or a signal number. Signal names are case insensitive and the SIG prefix is optional.

If a sigspec is 0 or EXIT, arg is executed when the shell exits. To understand it, close terminal & open it after editing following line in .bashrc file.

trap 'notify-send "Ctrl D pressed"' 0

Ctrl D is similar to exit command to exit from terminal.

If you want Bash to exit upon receiving the INT signal, even in interactive mode, you can add the following to your ~/.bashrc:

trap 'exit' INT

or

trap 'exit' 2
  • 1
    it seems legit !! – luv.preet Mar 8 '17 at 18:29

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.