跳到主要内容
ansicode

SU / SD — 向上 / 向下滚动

将屏幕内容向上(SU)或向下(SD)滚动 N 行,光标位置不变。

字节形式

涵盖所有常见的字符串字面量写法,方便正反查找。

\\x1b[\x1b[NS (scroll up) \x1b[NT (scroll down)
\\033[\033[1S / \033[1T
\\e[\e[1S / \e[1T
ESC [ESC [ N S / T
hex1b 5b <N> 53 / 54

说明

ECMA-48 §8.3.147(SU)与 §8.3.113(SD)。末字节 S = SU(Scroll Up)、T = SD(Scroll Down)。字节序列分别为 \x1b[<N>S\x1b[<N>T;N 省略时默认 1。两者把 *滚动区域内* 内容按 N 行平移,并以空行填补暴露出的行 —— SU \x1b[<N>S 让顶部 N 行消失、底部出现 N 行空白(与新文本自动滚屏方向相反),SD \x1b[<N>T 反之。关键细节:光标位置不变。与 CUU / CUD(cursor-move)正相反 —— 后者只移动光标不影响内容,SU / SD 只移动 *内容* 不动光标,是内容滚动原语,不是光标移动。若已通过 DECSTBM(\x1b[<top>;<bot>r,见 decstbm)限定滚动区域,则只滚动该区域内行;区域外的行原样冻结 —— 正是 TUI 把状态栏钉在原处、让日志视口滚动的依据。

可移植性 —— 在现代模拟器(xterm、iTerm2、kitty、alacritty、wezterm、gnome-terminal、Konsole、Ghostty、Windows Terminal、ConPTY 1809+、Linux console)上通用。最大解析陷阱是末字节 T 也被 xterm 鼠标追踪协议使用(CSI Pe ; Px ; Py ; Pv ; Ph T 高亮追踪,见 xterm-ctlseqs DECSET ?1001)。现代终端按参数个数消歧 —— 单参数 T 是 SD、多参数 T 是鼠标追踪 —— 但要从野外吞入未知 CSI 序列的解析器需同时处理两种形态。部分遗留模拟器实现了 SU 却未实现 SD;若 SD \x1b[T 在目标终端上视觉无效,回退是在区域顶部用 IL(\x1b[<N>L,见 csi-il)插入空行。tmux 原样转发 SU / SD,并尊重内部 pane 的滚动区域。

用法分工:SU 是主力 —— TUI 用它在不动光标的前提下滚动内容(日志查看器、分页输出、动态仪表板,让新数据滚入视野但光标停在状态行上)。SD 较少见;主要用于「倒带」动画,或在自定义 less 风格查看器中实现向上回滚而避免完整重绘成本。对比 LF(\n,见 c0-controls)—— 它在 *未受限* 区域底部发出时会滚动 *整屏*;SU 让你在 DECSTBM 限定的区域内滚动而不影响区域外的行,这正是分屏 TUI 得以存在的关键。对比 IL / DL(csi-il / csi-dl)—— 它们在 *光标行* 插入 / 删除行;SU / SD 对整个区域整体操作,IL / DL 对单一位置操作。相关:decstbm(DECSTBM —— 设定 SU / SD 操作的滚动区域)、cursor-move(CUU / CUD —— 只动光标不动内容的对照)、csi-il(IL —— 区域级 SD 的每行版伴侣)。

规范出处: ECMA-48 §8.3.147 (SU) / §8.3.113 (SD)

参数

S向上滚动 N 行
T向下滚动 N 行

示例

bash
printf 'top\nmid\nbot\033[2S'   # scroll region up 2
python
import sys; sys.stdout.write('\x1b[1S')
go
fmt.Print("\x1b[1S")
javascript
process.stdout.write('\x1b[1S')
c
printf("\x1b[1S");

在哪里用到

实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。

  • less, more pagers`d`(下半页)与 `u`(上半页)发 SU / SD 滚动视口而不重绘状态行
  • vim, neovim window scrolling`<C-d>` / `<C-u>` 与 `<C-e>` / `<C-y>` 映射到 DECSTBM 限定区域内的 SU / SD,使状态行钉住不动
  • htop, btop, glances dashboards进程列表的动态刷新通过 SU 把行向上滚动,而表头位于滚动区域外保持冻结
  • tmux, GNU screen split-pane redraws每个分屏运行各自的 DECSTBM 区域;每个 pane 的 SU / SD 局限于自身,不会泄漏到分隔条或其他 pane
  • ncurses wgetch — refresh loop emits SU to scroll the inner window without clearing the surrounding chrome

常见问题

针对这条序列,开发者真正会去搜索的问题的简短回答。

\x1b[1S 和在底行发一个 \n 有什么不同?
两点。(1)光标:SU 保持光标不动;底行的 LF 会把光标下移(虽随后会被终端钳制在底行,但部分模拟器的内部行计数仍发生改变)。(2)区域意识:SU 严格在 DECSTBM 滚动区域内操作 —— 区域外的行原样冻结。LF 只滚动未受限区域;若你通过 \x1b[<top>;<bot>r 缩小了滚动区域而光标停在区域外,LF 的行为由实现定义且常出意外。TUI 想要「让日志视口向上滚一行但状态栏和光标钉住不动」时,SU 一次同时满足两点。
为什么 \x1b[T(SD)有时会被识别为鼠标追踪上报?
末字节 T(0x54)被重载。带一个参数时是 SD —— \x1b[<N>T 将区域下滚 N 行;带五个参数(\x1b[<Pe>;<Px>;<Py>;<Pv>;<Ph>T)时则是 xterm 高亮追踪鼠标上报,来自 DECSET ?1001。现代模拟器按参数个数消歧,但只匹配 CSI ... T 而不计参数个数的临时解析器会误判其一。如果你写这样的解析器,在派发前数清 ; 分隔符。如果你向某个先前程序启用了高亮追踪却未关闭的终端发 SD,最好改用 IL 回退(在区域顶行发 \x1b[<N>L)以彻底规避歧义。

终端支持

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

相关序列

在家族食谱中

CSI 食谱 · 5. 边距与滚动区 —— DECSTBM `r` 与 DECSLRM `s`