OSC 8 — 内联超链接
在终端输出中渲染可点击超链接(gnome-terminal 3.26+、iTerm2、Windows Terminal、kitty 等)。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\x1b]8;;URI\x07TEXT\x1b]8;;\x07\033]8;;URI\007TEXT\033]8;;\007\e]8;;URI\aTEXT\e]8;;\aESC ] 8 ; ; URI BEL TEXT ESC ] 8 ; ; BEL1b 5d 38 3b 3b ... 07 ... 1b 5d 38 3b 3b 07实时预览
在浏览器中通过与解码器相同的分词器渲染 —— 无需打开终端。
说明
OSC 8 —— 内联超链接。由 gnome-terminal 作者 Egmont Koblinger 在 2017 年制定,现已被 iTerm2 3.5+、Windows Terminal 1.21+、kitty、wezterm、ghostty、Konsole 18.08+、libvte 0.50+(之后的 gnome-terminal / xfce4-terminal / tilix 全继承)以及 VS Code 集成终端采纳。两段式序列:\x1b]8;params;URI BEL(或以 ST \x1b\\ 结束)开始链接区段;\x1b]8;;BEL(URI 为空)结束。中间 TEXT 可包含任意可打印字节及后续 SGR —— 所以可以把链接套在 \x1b[4;34m…\x1b[0m 里得到熟悉的「蓝色 + 下划线」外观(iTerm2 / ghostty / wezterm / 近版 gnome-terminal 会渲染为真正可点击的链接)。可选参数:id=anchor 提示终端「具有相同 id 的相邻或非相邻字段属于同一逻辑链接」(用于跨行回卷的 URL 不让每个单元格变成独立超链接)。URI 范围:HTTP / HTTPS 在所有支持 OSC 8 的模拟器上可用;file:// 在 iTerm2 / wezterm / kitty / vscode-terminal 可用;编辑器 URI(vscode://、cursor:// 等)部分支持。
两类失败模式咬到 OSC 8 用户。(1)终止符卫生:OSC 序列必须显式以 BEL(\x07)或 ST(\x1b\\)结束;漏写终止符会让解析器把后续字节当作链接负载继续吞,直到字节流中下一处 BEL / ST 出现 —— 你之后的程序输出全被吞掉(见 osc-terminator)。为兼容 xterm 优先用 BEL,追求 ECMA-48 严谨用 ST —— 选一种并保持一致。(2)id= 语义分裂:Kitty 以 id + url 为去重键(同 id + 不同 url → 两个独立链接,这正是你要的);21.04 前 Konsole 和 3.36 前 gnome-terminal 仅按 id 去重(同 id + 第二个 url 静默继承最先出现的 url —— 数据损坏);iTerm2 完全忽略 id(每段各自独立);Windows Terminal 接受 id 但不跨行视觉聚合。同一会话内绝不要为两个不同 URL 重用同一 id= —— 从内容哈希或 uuid 生成 id(完整兼容性表见 osc8-id-rebind)。覆盖:Linux console / fbcon 与 Alacritty(有意省略)把整个 OSC 8 包络渲染为空 —— 链接文本会消失,不只是丢下划线。cmd.exe 与 Apple Terminal.app 渲染文本但不可点。这些栈上务必提供 URL 内联回退(或「链接文本(URL)」的形式)。
没有「关闭超链接」的精准 SGR —— 标准关闭就是空 URI 形式 \x1b]8;;\x07(或 \x1b]8;;\x1b\\)。组合 sgr-underline + sgr-fg-basic 给超链接包络内的可见文本上样式而不影响链接语义:\x1b]8;;https://example.com\x07\x1b[4;34mlink text\x1b[0m\x1b]8;;\x07。属于同一 OSC 家族、共用终止符规则的窗口标题与工作目录更新,见 osc-title 与 osc-cwd。OSC 52 剪贴板互操作见 osc-clipboard。发 OSC 8 时务必配合受众检查 —— 按保守行为假设(alacritty / Linux console 上文本会消失),并在 CLI 的 --help 或 -l 长格式模式里为这些用户提供文本 URL 回退。
规范出处: Hyperlinks in terminal emulators (gnome-terminal proposal, 2017)
示例
printf '\033]8;;https://example.com\033\\link text\033]8;;\033\\\n'print('\x1b]8;;https://example.com\x07link text\x1b]8;;\x07')fmt.Print("\x1b]8;;https://example.com\x07link text\x1b]8;;\x07\n")console.log('\x1b]8;;https://example.com\x07link text\x1b]8;;\x07')printf("\x1b]8;;https://example.com\x07link text\x1b]8;;\x07\n");在哪里用到
实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。
- gh (GitHub CLI)issue / PR / diff 输出链接到对应 github.com URL
- git 2.40+启用 color.hyperlink 后,部分子命令的文件路径会变成超链接
- eza在支持的终端中,文件名超链接到 file:// URI
- pytest — traceback file paths
- cargo build output — diagnostic URLs
- deltagit 分页器——文件路径头链接到磁盘上的文件
常见问题
针对这条序列,开发者真正会去搜索的问题的简短回答。
- 为什么
\x1b]8;;https://...\x1b\\在终端里显示成原始文本? - 你的终端没实现 OSC 8,或者你身处复用器中而 OSC 被吞掉。现代终端(iTerm2、kitty、ghostty、wezterm、alacritty、较新的 Windows Terminal / gnome-terminal)会渲染为可点击链接;老终端会按字节原样打印。tmux 必须
set -g allow-passthrough on才会转发——参见tmux-passthrough-dcs误区条目。 - 能用 BEL(
\a)代替 ST(\x1b\\)作为终止符吗? - 可以——两种终止符都符合规范,所有支持 OSC 8 的终端都接受。BEL 是 xterm 最早的写法,字节数更短;ST 是 ECMA-48 的标准形式。代码库里挑一种用并保持一致——在同一段 OSC 里混用是未定义行为。
- 为什么相邻的两条 OSC 8 链接被合并成了一条长链接?
- 你在两条链接之间漏写了关闭序列
\x1b]8;;\x1b\\(空 URL),或者两个不同 URL 复用了同一个id=…值,终端把它们当作一段。每条链接都要先关闭再开下一条,并且要么省略id=,要么每个 URL 用新值——参见osc8-id-rebind误区条目。
终端支持
- 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 部分 | 不支持 | 不支持 | 支持 | 支持 | 不支持 | 支持 | 不支持 | 支持 | 支持 | 支持 | 支持 | 部分 | 不支持 |