TBC — 清除制表位(CSI g)
清除一个或全部 tab 停位,改变 HT 和 CBT 的落点。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\x1b[g (clear current) \x1b[3g (clear all)\033[g / \033[3g\e[g / \e[3gESC [ Ps g1b 5b <Ps> 67说明
ECMA-48 §8.3.154 —— 制表位清除(TBC)。末字节 g(0x67)。参数控制范围:0(默认,省略时同)仅清除 *当前列* 的 tab 停位;3 清除整个终端中 *所有* tab 停位。字节序列 \x1b[g(清当前)与 \x1b[3g(清全部)。与 HTS(\x1bH,见 esc-hts,在当前列设置 tab 停位)配对 —— TBC 是它的「清除」对半。默认每 8 列一个 tab 停位(9、17、25 …);每个新开终端都以此网格起步,\x1b[3g 是把白板擦干净的原语,便于 HTS 重新铺设与表单 / 表格 / 列对齐输出匹配的自定义布局。
可移植性 —— xterm、iTerm2、kitty、alacritty、wezterm、gnome-terminal、Konsole、Ghostty、Linux console、Windows Terminal、ConPTY 1809+ 通用。Windows 旧 cmd.exe(ConPTY 之前)忽略 TBC。最常见的作者意外:一旦发出 \x1b[3g,HT(\t,0x09)就 *什么也不做* —— 没有 tab 停位可推进,光标原地不动;用 \t 排版的工具(column、pr、expand、Makefile 配方输出、不少 heredoc 格式化字符串)会静默输出错乱 / 左对齐的结果,直到重新设置停位。防御性写法:总是把 \x1b[3g 与一串 HTS 配对发送,再把控制权交还用户;切勿留下「停位全清、未设新位」的状态 —— 这是 TUI 崩溃后特别恶心的状态泄漏。terminfo tbc cap 存在,但终端条目很少填充;程序通常直接发字节。
清除状态在正常屏幕操作下持久存在 —— SGR 0、清屏(\x1b[2J)、Ctrl+L 换页(\x0c)甚至全新提示符都 *不会* 恢复默认 8 列网格。只有 DECSTR(\x1b[!p,见 decstr-soft-reset)、RIS(\x1bc,见 ris-reset)或另一次 TBC + HTS 序列能撤销。tmux 把内部 pseudo-terminal 的 tab 停位规范化为默认 8 列网格,因此 pane 内发出的 TBC 在多路复用器边界被截留而非转发到外层终端 —— 与 HTS 同形态,同一对警告也适用(重新接入会话时,tmux 感知的代码应重新发出期望的 tab 布局)。GNU screen 行为相同。相关:esc-hts(HTS —— 配套的「在此设置 tab 停位」一半)、csi-cbt(CBT —— \x1b[<N>Z 按停位后退 N 次,CHT 的对称对应)、c0-controls(C0 表,含 HT \x09 —— TBC 所控制的字面 tab 字符)。
规范出处: ECMA-48 §8.3.154 (TBC)
参数
| 0 | 清除当前列上的 tab 停位 |
| 3 | 清除所有 tab 停位 |
示例
printf '\033[3g' # clear all tab stops\nprintf '\033H' # set a tab stop here (HTS, ESC H)import sys; sys.stdout.write('\x1b[3g')fmt.Print("\x1b[3g")process.stdout.write('\x1b[3g')printf("\x1b[3g");在哪里用到
实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。
- vim / neovim `:set tabstop=N`缓冲区中途改 `tabstop` 会触发 `\x1b[3g`(TBC 模式 3 —— 清所有 tab 停止位),随后在每个新停止列发 HTS(`\x1bH`)—— `:redir @a` 在 `:set tabstop=4` 切到 `:set tabstop=8` 时可捕获
- GNU coreutils `expand` / `unexpand`写到真 TTY(vs 管道输出)的实现在转换前发 TBC 重置停止位,使 `expand --tabs=4 file` 在不同终端默认 tab 停止位(部分 VT 默认每 8、其他每 10)间保持确定性
- ed(1) `T` command (set tab)BSD ed 与 FreeBSD ed 通过发 `\x1b[g`(TBC 模式 0 —— 清当前列停止位)再重定位来实现历史 `T` 命令 —— 为 POSIX.1-2024 兼容性保留,现代 shell 中极少调用
- terminfo `tbc` capability (clear_all_tabs)在 `xterm-256color`、`linux`、`screen-256color` 等 ~280 个 terminfo 条目中,`tbc` 能力硬编码为 `\E[3g` —— `tput tbc` 解析为相同字节,被 initscripts 与 `tset` 用于登录时统一 tab 停止位
- Emacs `tab-width` buffer-local recalc缓冲区局部 `tab-width` 经 `set-variable RET tab-width RET` 修改时,重显引擎发出 TBC + HTS 对以对齐新停止位 —— `M-x untabify` 完成区域转换后也用同一模式确保后续 tab 按键对齐
常见问题
针对这条序列,开发者真正会去搜索的问题的简短回答。
\x1b[g和\x1b[3g有什么不同?\x1b[g(省参,等同\x1b[0g)只清除*当前光标列*的 tab 停位 —— 终端中其它停位不动。\x1b[3g清*全部*停位。无中间档:ECMA-48 §8.3.154 通过参数0与3仅定义两种范围,其它值保留且多数终端忽略。实际影响:CUP 定位到第 9 列后发\x1b[g只删除第 9 列的停位,17 / 25 / 33 / … 仍在,HT 仍按预期推进。\x1b[3g抹白板,之后 HT(\t)会失活,直到通过 HTS(\x1bH,见esc-hts)铺新停位。\x1b[3g之后如何恢复默认 8 列的 tab 网格?- 三种方案,破坏面递增。(1) 在每个期望列重发 HTS:CUP 到第 9 列,
\x1bH;CUP 到第 17 列,\x1bH;重复到终端宽度。这是唯一外科级方案 —— 不动其它 DEC 状态。(2) DECSTR 软复位(\x1b[!p,见decstr-soft-reset)—— 同时恢复光标可见性、origin 模式、autowrap 及多数 DEC 私有模式与 tab 停位;TUI 会话间安全使用,但会重置更多东西。(3) RIS 硬复位(\x1bc,见ris-reset)—— 还会清回滚与 SGR;应用内通常太激进。注意:清屏(\x1b[2J)、换页(\x0c)、SGR 0 都*不会*恢复 tab 停位 —— 这是 TBC 最常见的作者陷阱。
终端支持
- 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 支持 | 支持 | 支持 | 支持 | 支持 | 部分 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |