C0 控制字符 —— 单字节控制码
C0 控制码。0x20 以下的 32 个单字节控制码 —— BEL 0x07、BS 0x08、HT 0x09、LF 0x0a、CR 0x0d、ESC 0x1b、SI / SO 等。严格来说不算转义序列,但每个终端模拟器都会与 SGR / CSI 一同解析,且在任何含 ANSI 的日志中都会出现。
1 条序列
何时用 C0
需要单字节、完全不要 \x1b 引导的原语时——\b 回退一格、\t 跳到下一个 tab 停位、\n 喂一行、\r 回到第 1 列、\a 响铃——就用 C0 控制字符。它们是 ANSI / VT 出现之前 ASCII 留给终端控制的 7 位码,至今所有终端依旧内联响应。一字节即一动作(最小 CSI 至少三字节),这正是它们还活在你 printf 格式串里的原因。C0 也是其他家族的基底:\x1b 本身(ESC,0x1b)就是 C0 码,\a(BEL,0x07)则兼任 OSC 字符串的事实终止符。
C0 常用一行式
复制粘贴到 bash / zsh 即可运行 —— printf 会把 \x1b 解释为 ESC 字节。
敲响铃声 printf '\a'进度条(CR + 覆写) printf '\rdone: %d%%\n' 50HT 对齐两列表格 printf 'name\tsize\nbig\t1G\n'
C0 食谱 —— 四个不带 ESC 的单字节原语
C0 是早于 ESC 字符本身的家族 —— 每条码一字节、不带 \x1b 引导,从 1970 年的 VT05 到 2026 年的 Ghostty 所有终端都内联响应。下面四步覆盖你今天依旧会发的内容:组成行尾的 CR / LF 对、不擦除的 BS 光标回退、做制表对齐的 HT,以及兼任 OSC 字符串终止符的可闻铃 BEL。
1. CR + LF —— 行尾组合
CR(
\r,0x0d)光标回到当前行第 1 列;LF(\n,0x0a)光标下移一行。Unix tty 内核的onlcr模式在每个 LF 前隐式补 CR —— 这就是为什么交互 shell 里裸printf '\n'落在下一行第 1 列。关掉onlcr(stty -onlcr)后同样的\n会出现「阶梯」效应 —— 每行起点向右偏,因为没有重置列。在 alt-screen 内(\x1b[?1049h)内核onlcr被旁路 —— 渲染循环必须在行间显式发\r\n,否则光标走出屏幕右侧。Windows 控制台同理,CRLF 对就是字面行尾。\r单用则是经典进度条手法:printf '\r%d%%' "$pct"反复覆盖同一行。2. BS —— 光标回退一格但不擦除
退格(
\b,0x08)光标左移一列、不擦除所落的字符。打印abc再发\b,光标停在c上 —— 紧接着的x就地覆盖c。要真擦掉一字符,经典三字节序列是\b \b(退格、空格、退格)—— 退、涂空、再退。现代代码更多直接用\x1b[K(EL —— 从光标位置擦到行尾),但\b \b仍是 readline / GNU getline 处理密码掩码与就地编辑回显的方式。BS 也是 raw 模式下 Backspace 键通常发的码 —— 部分 terminfo 条目把它与 DEL(0x7f)互换,BS 与 DEL 的混淆正是「我的退格在响铃」/ Ctrl-H 笑话的根源。3. HT —— 水平制表与 TBC / HTS 渊源
水平制表(
\t,0x09)将光标前移到下一个登记为 tab 停位的列。默认网格每 8 列一个停位(1、9、17、25……),所以printf 'a\tb\tc'把a落在第 1 列、b在第 9 列、c在第 17 列。应用可用 HTS(\x1bH—— 在当前列登记新停位)与 TBC(\x1b[g清当前列 /\x1b[3g清全部停位)调整网格。HT + HTS + TBC 三者一起承袭 1970 年代打字机制表接口的整套语义,原封不动进入 ANSI。反向是 CBT(\x1b[Z)—— 回退一个停位,对应 Shift-Tab。要点:HT 不向缓冲区写入空格 —— 它只是移动光标,跨过已有内容。跳过一段文本后再在目的列发空格,看到的是新空格覆盖原内容,不是原内容保留。4. BEL —— 兼任 OSC 终止符的响铃字节
响铃(
\a,0x07)原本是电传打字机的铃声字节。现代终端把它处理成可闻 beep、视觉闪烁,或通知徽章 —— 由各应用偏好控制(xterm的bellIsUrgent、iTerm2 的 *Profiles → Terminal → Silence Bell*、kitty 的enable_audio_bell等)。它的第二条命远更重要:BEL 是 OSC 序列两种标准字符串终止符之一。\x1b]0;title\x07设置窗口标题;尾随的\x07就像 ST(\x1b\\)一样关闭 OSC 字符串。xterm 与所有衍生都接受 BEL 终止的 OSC,因此几乎所有 CLI 工具都用它而非 ECMA-48 正统的 ST。代价:你的工具在 OSC 信封之外发 BEL 而用户终端铃声开启时,会突如其来一声叮咚。防御提示:很多模拟器(Konsole、gnome-terminal、kitty)专门抑制 OSC 信封内的 BEL —— 信封内静默、信封外响铃 —— 但旧的 Linux 控制台两边都会响。若你的 CLI 既发可见诊断又发 OSC 标题,在打开铃声的xterm -e ./your-cli下跑一遍以确认。