Why do terminals sometimes echo special characters like ^C?

Run this, it's just a terminal setting, by default, everything you type is echoed :

stty -ctlecho

Now, your terminal is set to not display these characters.

man stty | less +/ctlecho

[-]ctlecho
echo control characters in hat notation ('^c')

To keep this configuration permanently, add it to your *rc file. (~/.bashrc or such).

To list stty settings, just type the command alone.


The character is echoed back because you have the ECHO flag on in the terminal settings, and is echoed in the ^C form because you also have the ECHOCTL flag on. Both flags are on by default on most systems. You can turn them on and off by using their lowercase form with the stty(1) utility:

stty -echoctl # turn echoctl off
stty echoctl  # turn echoctl on

You can refer to the termios(3) manpage on Linux for a description [1]:

ECHOCTL (not in POSIX)

If ECHO is also set, terminal special characters other than TAB, NL, START, and STOP are echoed as ^X, where X is the character with ASCII code 0x40 greater than the special character. For example, character 0x08 (BS) is echoed as ^H. [requires _BSD_SOURCE or _SVID_SOURCE]

Notice that turning just the ECHOCTL flag off will not prevent control characters from being echoed back, but will cause them to be echoed back in their raw form, rather than in the ^X caret form. The fact that a character is special and will generate a signal (eg. ^C -> VINTR -> SIGINT) does not affect in any way whether it will be echoed back or not.

Most terminal emulators will not display the control characters in any way (unfortunately), but they may interpret them in funny ways: for an illustrative example, start a command like sleep 3600 or cat > /dev/null, then on the next line press the <Escape>[41m foo<Enter> keys. With echoctl on, you'll have ^[[41m foo printed on your screen, and nothing special will happen. But with echoctl off, the terminal will interpret the echoed back <Raw_esc>[41m as an ANSI color escape (without displaying any of the [41m, etc) and will turn the background red.

Depending on the terminal emulator and its settings, an emacs user pressing ^N by reflex may end up switching to the alternate character set, and turn all the letters into line-drawing squiggles.

You usually don't want these to happen, thence ECHOCTL can be considered a reasonable default.


[1] That description is not very accurate:

  • It's not the "terminal special characters" which are echoed in that caret form, but the control characters (ASCII 0x0 - 0x1f and 0x7f), no matter if they're special or not. If you define Q as the VINTR "terminal special character" (replacing the default ^C, eg. with stty intr Q), it will still be echoed back as simply Q, not as ^Q or chr(0x91).

  • On Linux, VEOF will not be echoed back (as ^D or in any other form) when the ICANON flag is also set. But it will be echoed back in that case too on *BSD and MacOS.

  • ASCII 0x7f (DEL) will not be displayed as char + 0x40 (as described), but as char ^ 0x40 (^?). Just like all the others, btw ;-)