Skip to main content
ansicode

C1 controls — 8-bit single-byte equivalents of ESC sequences (0x80–0x9F)

The 8-bit C1 control bytes (0x80..0x9F) — CSI, OSC, ST, DCS, NEL, HTS, IND, RI — and their 7-bit ESC <letter> equivalents.

Byte forms

Every common string-literal form so you can paste-and-search either direction.

\\x1b[\x9b CSI \x9d OSC \x9c ST \x90 DCS \x85 NEL \x88 HTS \x84 IND \x8d RI
\\033[\233 / \235 / \234 / \220 / \205 / \210 / \204 / \215
\\e[(no \e form — these are single 8-bit bytes; use the 7-bit ESC equivalents below)
ESC [ESC [ ≡ CSI / ESC ] ≡ OSC / ESC \\ ≡ ST / ESC P ≡ DCS / ESC E ≡ NEL / ESC H ≡ HTS / ESC D ≡ IND / ESC M ≡ RI
hex9b / 9d / 9c / 90 / 85 / 88 / 84 / 8d

Description

The C1 control set occupies bytes 0x80..0x9F and provides single-byte alternatives to the most common ESC <letter> sequences. The full set: IND (0x84, ESC D — line feed without CR), NEL (0x85, ESC E — CR+LF), HTS (0x88, ESC H — set tab stop at cursor column), RI (0x8D, ESC M — reverse line feed, scroll if at top), SS2 (0x8E, ESC N — single-shift G2 charset for the next char), SS3 (0x8F, ESC O — single-shift G3), DCS (0x90, ESC P — Device Control String introducer), CSI (0x9B, ESC [ — Control Sequence Introducer, the most common one), ST (0x9C, ESC \\ — String Terminator for DCS / OSC / APC / PM / SOS), OSC (0x9D, ESC ] — Operating System Command introducer), PM (0x9E, ESC ^ — Privacy Message), APC (0x9F, ESC _ — Application Program Command, used by Kitty's graphics protocol). Avoid the 8-bit forms on modern terminals: every byte in 0x80..0x9F is a UTF-8 *continuation byte* (the first bits are 10xxxxxx), so a stray 0x9B in a UTF-8 stream is either consumed as part of an invalid sequence or silently dropped. Always emit the 7-bit ESC <letter> form (\x1b[, \x1b], \x1b\\, etc.) — it is unambiguous in UTF-8, ASCII, and Latin-1, and every terminal recognises it. The 8-bit C1 set is relevant mainly to legacy contexts (DEC VT220 in S8C1T mode, ISO 8859-1 stream archives, old VT100 firmware test vectors).

Spec citation: ECMA-48 §5.2 (C1 set) / ISO 6429

Parameters

IND (0x84, ESC D)index — cursor down 1 (LF without CR); scroll if at bottom of region
NEL (0x85, ESC E)next line — CR + LF combined
HTS (0x88, ESC H)horizontal tab set — set tab stop at current cursor column
RI (0x8D, ESC M)reverse index — cursor up 1; scroll if at top of region
SS2 (0x8E, ESC N)single shift G2 — use G2 charset for next char only
SS3 (0x8F, ESC O)single shift G3 — use G3 charset for next char only
DCS (0x90, ESC P)device control string introducer — terminated by ST
CSI (0x9B, ESC [)control sequence introducer — the most common form
ST (0x9C, ESC \\)string terminator — closes DCS / OSC / APC / PM / SOS
OSC (0x9D, ESC ])operating system command — terminated by ST or BEL
PM (0x9E, ESC ^)privacy message — terminated by ST
APC (0x9F, ESC _)application program command — terminated by ST (Kitty graphics)

Examples

bash
# 7-bit (preferred — UTF-8 safe):\nprintf '\033[31mred\033[0m'\nprintf '\033]0;new window title\033\\\\'\n# 8-bit C1 (legacy — breaks under UTF-8):\nprintf '\x9b31mred\x9b0m'   # only works if terminal is in 8-bit mode + Latin-1
python
# Prefer 7-bit ESC form:\nimport sys; sys.stdout.write('\x1b[31mred\x1b[0m')\n# 8-bit C1 — fails on UTF-8 stdouts:\n# sys.stdout.buffer.write(b'\x9b31mred\x9b0m')
go
// 7-bit ESC form (UTF-8 safe):\nfmt.Print("\x1b[31mred\x1b[0m")\n// 8-bit C1 — emits two UTF-8 continuation bytes interpreted as garbage:\n// os.Stdout.Write([]byte{0x9b, '3','1','m'})
javascript
process.stdout.write('\x1b[31mred\x1b[0m');\n// process.stdout.write(Buffer.from([0x9b, 0x33, 0x31, 0x6d]))  // breaks UTF-8
c
/* 7-bit ESC form: */\nprintf("\x1b[31mred\x1b[0m");\n/* 8-bit C1 — only safe on Latin-1 / explicit 8-bit terminals: */\n/* fputc(0x9b, stdout); fputs("31m", stdout); */

Used in

Real-world tools that emit this sequence — anchors the bytes to commands you've already used.

  • telnet, tn5250, x3270 (mainframe / AS-400 emulation)8-bit IBM 5250 / 3270 streams send CSI as the single byte `\x9b` instead of `\x1b[`
  • minicom, picocom (8-bit serial sessions)VT220-era hardware terminals in 8-bit mode produce raw C1 bytes — `\x9b` for CSI, `\x90` for DCS, `\x9d` for OSC
  • luit (X11 locale filter)the locale-to-UTF-8 wrapper that normalises incoming C1 bytes to their `ESC <Fe>` 7-bit equivalents before forwarding to the emulator
  • GNU screen — accepts incoming C1 bytes and re-emits the 7-bit form on UTF-8 PTYs
  • kermit, lrzsz file-transfer protocolsframing bytes overlap the C1 range on legacy 8-bit terminal links

Frequently asked

Short answers to the questions developers actually search for this sequence.

When should I emit C1 CSI \x9b instead of \x1b[?
Almost never on a modern UTF-8 terminal. The byte 0x9B is a valid UTF-8 continuation byte and collides catastrophically with any multibyte character that happens to contain it — your CSI introducer gets eaten as part of a malformed UTF-8 sequence and the parameters render as text. The 7-bit form \x1b[ (ESC [) is universally understood and survives every encoding (UTF-8, Latin-1, ASCII). Only emit 8-bit C1 when you're certain the channel is 8-bit clean and non-UTF-8 (e.g. some legacy serial / DEC VT510 setups with S8C1T explicitly enabled).
Why does Linux console disagree with xterm on C1 handling?
Linux fbcon ships in S7C1T mode (7-bit C1 transmission only) by default and treats raw bytes in 0x800x9F as graphic characters from its loaded font, not as C1 controls. xterm defaults to S8C1T-aware: it parses 0x9B as CSI, 0x9D as OSC, 0x90 as DCS, etc. The portable choice is to always emit the 7-bit equivalents (ESC [, ESC ], ESC P) — they work on both. If you actually need to know which mode the terminal is in, query with DECRQM for mode 66 (S7C1T/S8C1T select) — but the answer is mostly trivia; just emit 7-bit and move on.

Terminal support

xterm
partial
Linux console (fbcon)
no
macOS Terminal.app
no
iTerm2
no
Windows Terminal
no
cmd.exe / ConPTY
no
kitty
no
alacritty
no
WezTerm
no
Ghostty
no
GNOME Terminal
no
Konsole
no
tmux
yes
GNU screen
yes

Related sequences

In the family cookbook

ESC cookbook · 5. Locking shifts + the 8-bit C1 bridge — `\x1bn` / `\x1bo` / `\x1b|` and `\x80-\x9F`