You interact with a terminal or terminal emulator through a serial line or pseudo-tty device (which emulates a serial line).
Though there is a software module in the kernel that sits in the middle as a kind of adaption layer and does some transformation (discussed briefly later), you typically:
- send a stream of bytes to the terminal over that serial line which the terminal interprets either as glyphs to render on its screen or special instructions to change its behaviour
- in return, the terminal sends a stream of bytes to the computer over another wire on that serial line to tell the computer what you typed or to respond to some of the control queries it received.
For instance, a terminal could be configured as a ISO8859-1 (aka latin1 terminal) which means that when it receives the 0x53 0x74 0xe9 0x70 0x68 0x61 0x6e 0x65, it interprets it as rendering the
e glyphs at the current cursor position on its screen. And conversely, when the user types S, the terminal sends the 0x53 byte.
Byte values in the range 0 to 0x1f are interpreted as control characters. That is, they are not represented as glyphs, but have special meaning.
- 0x7 (BEL) generate an audio or video alert
- 0x8 (BS) moves the cursor to the left
- 0xa (LF) moves the cursor down
- 0xd (CR) moves the cursor to the first column of the screen
- 0x9 (TAB) moves the cursor to the next tabulation
There are only 32 control characters in that range and most terminals have many more features or way you can control them. So beside those, you can send sequences of more than one byte to control your terminal. For most terminals and for most of those sequences, the first byte is 0x1b (ESC) followed by one or more bytes.
For instance, while there are control characters to move the cursor left or down as seen above, there is none to move it to the right or up (as originally, in tele-typewriters, right would be done with "space", but in CRT terminals that erases what's under the cursor, and you wouldnt go up with a tele-typewriter as that would likely create a paper jam), so escape sequences had to be introduced for those, on most terminals 0x1b 0x5b 0x43 and 0x1b 0x5b 0x41 respectively (incidently, that's also the byte sequence many terminals send upon pressing the Right and Up for those that have such keys).
Now among the escape sequences that terminals support are some that:
- change the text or background colour and other graphic rendering attributes
- change the charset. For instance, there's no Greek character in latin1, and terminals (from the pre-Unicode days and still today) support switching to a different charset to display letters of other languages, or box drawing characters.
- set the position of tab stops
- can query information from the terminal such as the cursor position, colour, window title, size...
- can affect how input is processed. For instance, some terminals support entering a mode whereby upon pressing Shift+A for instance, it doesn't send a 0x41 (ASCII
A) character but a sequence of bytes that encodes information about modifiers (shift, alt, ctrl...) and keycode.
- some X11 terminal emulators recognise escape sequences to change the font, the window size, display JPEG images, send the screen contents to a printer...
In a text file, you usually only have bytes (or byte sequences if UTF-8 or other multibyte charsets) representing graphical characters. The only control characters you'll find in text files are NL (0xa, aka LF) and TAB (0x9).
When you do
cat just reads the contents of
file.txt and writes it to its stdout. If stdout is a serial or pseudo-tty device file (
/dev/pts/0 for instance) that has a terminal line discipline pushed onto it as would be the case if you run that command from an interactive shell in a terminal emulator, the line discipline translates those NLs to CR+NL (though NLNL may be translated to just CRNLNL) so the terminal upon receiving CRNL will move the cursor to the start and then down.
So the text in the contents of the file will be displayed on the terminal screen provided the text in the file is encoded in the character set of the terminal.
Now, bytes in executable files or other random binary files are not intended to represent characters, they can have any value including ones in the range 0 to 31, so when sent to a terminal, the terminal will do what it's told and interpret them as control characters, which may make it do anything as listed above and much more and render it completely unusable.
To guard against that, first you don't send those files to a terminal as that wouldn't make sense, or if you don't know whether a file may be a text file (or a file intended to be viewed verbatim by a terminal with escape sequences intended to be interpreted by a terminal) or not, you can use a tool that either removes the control characters (at least all those but TAB and NL) or give them a visual graphical representation.
That's what the
-t options as supported by many
cat implementations do. Where with
-v, all but NL and TAB are converted to some
^X notation for bytes 0 to 31 and 0x7f,
M-^X for bytes 0x80 to 0x9f and 0xff and
M-X for bytes 0xa0 to 0xfe which are common visual representations of non-ASCII characters. And
-t does it just for TAB (changed to
Or you can use a pager such as
view which do that by default (at least as long as you don't use the
-R raw options) and are a bit smarter in that they don't transform non-ASCII characters that are meant to have graphical representations in your locale and make it clearer what bytes have been transformed by using colouring or standout modes.
Or you can use tools dedicated to previewing non-text files such as
hexdump -C or
See also the
l command of
sed which does something similar to
cat -vte and is standard (contrary to
cat -vte) in a less ambiguous way:
sed -n l < a-file