When you press Ctrl+X, your terminal emulator writes the byte 0x18 to the master side of the pseudo-terminal pair.
What happens next depends on how the tty line discipline (a software module in the kernel that sits in between the master side (under control of the emulator) and the slave side (which applications running in the terminal interact with)) is configured.
A command to configure that tty line discipline is the stty
command.
When running a dumb application like cat
that is not aware of and doesn't care whether its stdin is a terminal or not, the terminal is in a default canonical mode where the tty line discipline implements a crude line editor.
Some interactive applications that need more than that crude line editor typically change those settings on start-up and restore them on leaving. Modern shells, at their prompt are examples of such applications. They implement their own more advanced line editor.
Typically, while you enter a command line, the shell puts the tty line discipline in that mode, and when you press enter to run the current command, the shell restores the normal tty mode (as was in effect before issuing the prompt).
If you run the stty -a
command, you'll see the current settings in use for the dumb applications. You're likely to see the icanon
, echo
and echoctl
settings being enabled.
What that means is that:
icanon
: that crude line editor is enabled.
echo
: characters you type (that the terminal emulator writes to the master side) are echoed back (made available for reading by the terminal emulator).
echoctl
: instead of being echoed asis, the control characters are echoed as ^X
.
So, let's say you type A B Backspace-aka-Ctrl+H/? C Ctrl+X Backspace Return.
Your terminal emulator will send: AB\bC\x18\b\r
. The line discipline will echo back: AB\b \bC^X\b \b\b \b\r\n
, and an application that reads the input from the slave side (/dev/pts/x
) will read AC\n
.
All the application sees is AC\n
, and only when your press Enter so it can't have any control on the output for ^X
there.
You'll notice that for echo, the first ^H
(^?
with some terminals, see the erase
setting) resulted in \b \b
being sent back to the terminal. That's the sequence to move the cursor back, overwrite with space, move cursor back again, while the second ^H
resulted in \b \b\b \b
to erase those two ^
and X
characters.
The ^X
(0x18) itself was being translated to ^
and X
for output. Like B
, it didn't make it to the application, as we deleted it with Backspace.
\r
(aka ^M
) was translated to \r\n
(^M^J
) for echo, and \n
(^J
) for the application.
So, what are our options for those dumb applications:
- disable
echo
(stty -echo
). That effectively changes the way control characters are echoed, by... not echoing anything. Not really a solution.
- disable
echoctl
. That changes the way control characters (other than ^H
, ^M
... and all the other ones used by the line editor) are echoed. They are then echoed as-is. That is for instance, the ESC character is send as the \e
(^[
/0x1b
) byte (which is recognised as the start of an escape sequence by the terminal), ^G
you send a \a
(a BEL, making your terminal beep)... Not an option.
- disable the crude line editor (
stty -icanon
). Not really an option as the crude applications would become a lot less usable.
- edit the kernel code to change the behaviour of the tty line discipline so the echo of a control character sends
\e[7m^X\e[m
instead of just ^X
(here \e[7m
usually enables reverse video in most terminals).
An option could be to use a wrapper like rlwrap
that is a dirty hack to add a fancy line editor to dumb applications. That wrapper in effect tries to replace simple read()
s from the terminal device to calls to readline line editor (which do change the mode of the tty line discipline).
Going even further, you could even try solutions like this one that hijacks all input from the terminal to go through zsh's line editor (which happens to highlight ^X
s in reverse video) relying on GNU screen's :exec
feature.
Now for applications that do implement their own line editor, it's up to them to decide how the echo is done. bash
uses readline for that which doesn't have any support for customizing how control characters are echoed.
For zsh
, see:
info --index-search='highlighting, special characters' zsh
zsh
does highlight non-printable characters by default. You can customize the highlighting with for instance:
zle_highlight=(special:fg=white,bg=red)
For white on red highlighting for those special characters.
The text representation of those characters is not customizable though.
In a UTF-8 locale, 0x18 will be rendered as ^X
, \u378
, \U7fffffff
(two unassigned unicode code points) as <0378>
, <7FFFFFFF>
, \u200b
(a not-really printable unicode character) as <200B>
.
\x80
in a iso8859-1 locale would be rendered as ^�
... etc.
The circumflex (^
) was equated to the up-arrow character on teleprinters. By the time SunOS and so forth came around, this part was more than 10 years in the past. The same character (replacement) was used in mathematical expressions, e.g., ^
for powers (where some others might use **
). It was also used in Pascal to indicate pointers.
Used for indicating control characters, this dates (at least) before 1980. You can find it used in DEC documentation for instance (it was certainly in use by the mid-1970s when I used teco. The Utilities manual from 1973 (page 927) shows a controlC for instance.
Looking for a suitable source, I find Teletypewriter Communication Codes by Gil Smith which says enough to place this in the late 1960s (demonstrating that the origin is pre-Unix, as well):
ASCII-63 was mostly identical to the current ASCII-67 version. The definitions of the control characters (col-1
above) varied between the two versions, as defined below. Also, in ASCII-63, the upper 32 positions (col-4) were
undefined, except for three: RUB (0x7F), ACK (0x7C), and ESC (0x7E). There are inconsistent references to an
ALT-MODE char (0x7D) in ASCII-63. In the 1967 version, RUB became DEL and stayed in the same position,
but ACK and ESC moved into the control character area (col-1). In ASCII-67, ^ replaced the up-arrow symbol,
and _ replaced the left-arrow
ASCII-63 and ASCII-67 are the common variants of ASCII, but there appear to have been some transitional
versions as well: in the Teletype Model 33 manual, there are references to a 1965 version of ASCII, that had SS in
place of SUB (0x1A), \ for @ (0x40), ~ for \ (0x5C), an odd character in place of | (0x7C), and | for ~ (0x7E). A
Teletype code card for M33 and M35 machines indicates a 1966 version of ASCII, though the printable characters
shown on the card were identical in all versions.
This used to be well-known, due to the problems of interchanging files between different encodings such as ASCII and EBCDIC where there were still printers capable of rendering up-arrows as such long after the character no longer existed in ASCII.
Best Answer
The character sets used historically with Unix, including ASCII, don’t have a tick character, so it wasn’t used. As far as I’m aware no common usage for that character has been introduced since it’s become available; nor would it, since it’s not included in POSIX’s portable character set.
` was apparently originally included in ASCII (along with ^ and ~) to serve as a diacritic. When ASCII was defined, the apostrophe was typically represented by a ′-style glyph (“prime”, as used for minutes or feet) rather than a straight apostrophe ', and was used as a diacritic acute accent too.
Historically, in Unix shell documentation, ` was referred to as a grave accent, not a backtick. The lack of a forward tick wouldn’t have raised eyebrows, especially since ' was used as the complementary character (see
roff
syntax).