C0 控制字符 —— BS、HT、LF、CR、BEL(单字节码)
无需 ESC 引导即可移动光标或触发事件的单字节 C0 控制字符。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\\x1b[
\x08 BS \x09 HT \x0a LF \x0d CR \x07 BEL\\033[
\010 / \011 / \012 / \015 / \007\\e[
\b / \t / \n / \r / \aESC [
BS / HT / LF / CR / BELhex
08 / 09 / 0a / 0d / 07说明
这五个单字节控制字符早于 ANSI/VT,至今所有终端仍直接响应它们:BS(0x08,\b)光标左移一格(不擦除 —— 配合空格再退格才能擦除,或使用 EL)。HT(0x09,\t)光标移到下一个 tab 停位(默认每 8 列)。LF(0x0a,\n)光标下移一行(在 onlcr tty 模式下还会回到第 1 列 —— Unix shell 依赖此特性,否则 \n 在 stty -onlcr 下会显得阶梯排列)。CR(0x0d,\r)光标回到当前行第 1 列 —— 进度条常用「\r + 重绘」模式。BEL(0x07,\a)发出可闻铃声或视觉闪烁,取决于终端设置;同时也是 OSC 字符串的事实标准终止符(见 OSC 0/2 与 OSC 8)。它们都不需要 ESC 字节 —— 属于继承自 ASCII(1963)/ ECMA-6 的 C0 控制集。
规范出处: ECMA-48 §8.2 (C0 set) / ASCII / ECMA-6
参数
| BS (0x08) | 退格 —— 光标左移 1 |
| HT (0x09) | 水平制表 —— 到下一个 tab 停位 |
| LF (0x0a) | 换行 —— 向下 1 行 |
| CR (0x0d) | 回车 —— 到第 1 列 |
| BEL (0x07) | 响铃 —— 可闻/可见提示;OSC 终止符 |
示例
printf '\rprogress: 50%%\r' # CR redraws current line\nprintf 'beep\a\n' # BEL rings the bellimport sys, time\nfor i in range(101):\n sys.stdout.write(f'\r{i}%'); sys.stdout.flush(); time.sleep(0.02)fmt.Print("\rprogress: 50%\r")process.stdout.write('\rprogress: 50%\r')printf("\rprogress: 50%%\r");在哪里用到
实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。
- npm, pnpm, pip, cargo progress bars每次进度刷新都发 `\r` 原地重绘——所有语言的包管理器通用
- tput bel, printf '\a'shell 脚本通过响铃提示错误或任务完成
- readline, GNU bash, zsh line editorcooked 模式编辑用 `\b`(BS)退格;cooked 模式下 `\n` 经 `onlcr` 翻译为 `\r\n`
- column, expand, cat -T`\t`(HT)是 coreutils 各工具普遍解析的表格分隔符
- asciinema, script — record the raw byte stream including all C0 controls
常见问题
针对这条序列,开发者真正会去搜索的问题的简短回答。
- 如何让
\a(BEL)触发屏幕闪烁而非发出声音? - 这是终端的偏好设置,不是序列变化 ——
\x07(BEL)由模拟器派发,由它决定按系统铃声响起还是窗口闪烁。xterm 有bellIsUrgent+visualBellX 资源,iTerm2 在每个配置文件中提供 *Visual bell* 选项,Windows Terminal 在settings.json里通过bellStyle: "visual"控制,gnome-terminal / Konsole 在配置对话框里有 *Visual bell* 复选框,kitty / wezterm / alacritty 都暴露enable_audio_bell/audible-bell。若程序要 *强制* 闪屏而不管终端配置,可发\x1b[?5h\x1b[?5l(DECSCNM 开/关 —— 屏幕反相模式),多数模拟器会渲染为单帧视觉闪烁。 - 为什么
\r在我的代码里表现为\r\n,但在 raw 模式下又只是裸回车? - POSIX 终端在 tty 行规程里插入
onlcr/opost翻译——当输出处理开启(cooked 模式默认)时,单独的\n会在抵达模拟器前被重写为\r\n。stty raw(或任何调用cfmakeraw()的 TUI)会清掉OPOST,于是你的字节按原样到终端:\n仅是纯换行(光标下移,列不变),必须自己发\r才能回到第 1 列。这就是为什么 raw 模式 TUI 的进度条循环显式用\r(或\x1b[1G,见cursor-column),而不依赖\n。在stty -onlcr下输出阶梯排列的反向症状根因相同。
终端支持
- xterm
- 支持
- Linux console (fbcon)
- 支持
- macOS Terminal.app
- 支持
- iTerm2
- 支持
- Windows Terminal
- 支持
- cmd.exe / ConPTY
- 支持
- kitty
- 支持
- alacritty
- 支持
- WezTerm
- 支持
- Ghostty
- 支持
- GNOME Terminal
- 支持
- Konsole
- 支持
- tmux
- 支持
- GNU screen
- 支持
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |