19

The program ed, a minimal text editor, cannot be exited by sending it an interrupt through using Ctrl-C, instead printing the error message "?" to the console. Why doesn't ed just exit when it receives the interrupt? Surely there's no reason why a cryptic error message is more useful here than just exiting. This behavior leads many new users into the following sort of interaction:

$ ed
hello
?
help
?
exit
?
quit
?
^C
?
^C
?
?
?
^D
$ su
# rm -f /bin/ed

Such a tragic waste—easily avoidable if ed simply agreed to be interrupted.

Another stubborn program exhibiting similar behavior is less which also doesn't appear to have much reason to ignore C-c. Why don't these programs just take a hint?

  • 4
    Interactive applications are not the same as non-interactive. The Ctrl-C behavior you are used to is the default for non-interactive ones. The interactive ones may override the behavior of Ctrl-C for their own purposes. – jw013 Aug 17 '14 at 0:32
  • 4
    Also, not sure if joke – jw013 Aug 17 '14 at 0:34
  • @jw013 Yes, the "typical session" was a joke (I couldn't find that one for some reason) but my question is serious. What I don't understand is why these applications choose to override the behavior of Ctrl-C if it doesn't actually provide anything useful. – Lily Chung Aug 17 '14 at 0:36
18

Ctrl+C sends SIGINT. The conventional action for SIGINT is to return to a program's toplevel loop, cancelling the current command and entering a mode where the program waits for the next command. Only non-interactive programs are supposed to die from SIGINT.

So it's natural that Ctrl+C doesn't kill ed, but causes it to return to its toplevel loop. Ctrl+C aborts the current input line and returns to the ed prompt.

The same goes for less: Ctrl+C interrupts the current command and brings you back to its command prompt.

For historical reasons, ed ignores SIGQUIT (Ctrl+\). Normal applications should not catch this signal and allow themselves to be terminated, with a core dump if enabled.

  • @Kzqai No, normal applications should not catch SIGQUIT, it's meant as an emergency exit. – Gilles Nov 2 '16 at 17:23
  • Ah, gotcha. Alright, retracted. – Kzqai Nov 3 '16 at 21:21
17

The Unix V7 ed(1) source code is a primitive 1,762-line C program with just a few comments, one of which is this highly-enlightening header comment:

/*
 * Editor
 */

Given that the source code itself does not provide any rationale, you're only going to get it from the program's author.

ed was originally written by Ken Thompson in PDP-11 assembly, but you'd actually need to talk to whoever ported it to C. That might have been Dennis Ritchie, since he created C for Unix, and was one of many who used C to make Unix portable to non-PDP machines. Dr Ritchie is no longer around to answer such questions, though.

My reading of the code suggests that it was done to try and preserve the contents of the in-core copy of the edited document. You'll notice that other text editors also do not die on Ctrl-C.

Here's what ed does on Ctrl-C:

onintr()
{
    signal(SIGINT, onintr);
    putchr('\n');
    lastc = '\n';
    error(Q);
}

(Yes, K&R C. We don't need no steenkin' return type specifiers or parameter declarations.)

Translated into English, ed:

  1. Re-registers the signal handler.

    (Unix didn't get auto-resetting signals until 4.3BSD, in the mid-1980s.)

  2. Writes out a new line, and remembers that it did so, via the global variable lastc.

    (ed.c has about sixty global variables.)

  3. Calls the error() function, which famously does little more than print ?, from the user's perspective.

In other words, it's saying, "You didn't really mean to do that, did you?"

  • 2
    Also worth noting that a lot of text editors do not exit on Control-C. Vim also doesn't. Neither does nano. I don't think emacs does, either, but don't have it installed to test. – derobert Aug 17 '14 at 1:02
  • 3
    @derobert Vi treats Ctrl+C the Unix way: go back to the toplevel. Emacs has its own keybindings, due to its non-Unix origins; the Emacs equivalent of Unix's Ctrl+C is Ctrl+G (the bell character — ring the bell at the computer to interrupt it) – Gilles Aug 17 '14 at 1:09
  • @derobert: Fair point. I've added this to the answer. – Warren Young Aug 17 '14 at 1:12
  • 2
    @Gilles: One of the side effects of calling error(s) in ed.c is to return to the main processing loop. It does so with a longjmp() call. shudder – Warren Young Aug 17 '14 at 1:14
  • Thank you for the details and the history lesson. This was a great read! – alichaudry Nov 17 '16 at 0:09
7

ed, like other interactive programs, use Ctrl+C to interrupt tasks of the program itself.
This is very similar to the normal case, where it interrupts a task running in the shell - a command.

From the user perspective, both variants are very similar. The handling of the signal is different: in the usual case, the signal SIGINT is sent to the foreground process, a running command, and the command handles it by exiting.
In the case of ed, the signal is sent to the foreground process, the ed instance. If there is a task running in ed, it is interrupted and the prompt is shown. If there is no task running, nothing is changed.

Note how a shell also does not exit on Ctrl+C, just like ed. And that it does exit on Ctrl+D. Again, just like ed

3

There are three signals that ed cares about:

  1. INT
  2. HUP
  3. QUIT

The POSIX specification of ed says the following about these:

SIGINT

The ed utility shall interrupt its current activity, write the string ?\n to standard output, and return to command mode (see the EXTENDED DESCRIPTION section).

SIGHUP

If the buffer is not empty and has changed since the last write, the ed utility shall attempt to write a copy of the buffer in a file. First, the file named ed.hup in the current directory shall be used; if that fails, the file named ed.hup in the directory named by the HOME environment variable shall be used. In any case, the ed utility shall exit without writing the file to the currently remembered pathname and without returning to command mode.

SIGQUIT

The ed utility shall ignore this event.

So whatever implementation of ed you are using, it conforms to the POSIX specification with regards to the INT signal (which is what Ctrl+C sends).

In this regard, the editor behaves like an interactive shell, which also does not terminate upon receiving the INT signal. Other editors, such as vi and nano does the same thing.

  • 1
    Some program implementations deliberately contradict POSIX, so it might be useful to explain the rationale for the standard / the cost of breaking it in this case. stackoverflow.com/questions/38605463/… – sourcejedi May 8 '18 at 8:41
  • 1
    @sourcejedi The standard does not say anything about the signals in its rationale. I have found no rationale saying anything about why the standard is followed in the sources of ed that I have available. It behaves in a similar manner as the shell, which also does not terminate on receiving the INT signal. – Kusalananda May 8 '18 at 10:41

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.