OSC 9 — 桌面通知(iTerm2 / Windows Terminal)
从终端触发原生桌面通知 —— 长任务完成、构建结束等场景。
字节形式
涵盖所有常见的字符串字面量写法,方便正反查找。
\\x1b[
\x1b]9;MESSAGE\x07\\033[
\033]9;MESSAGE\007\\e[
\e]9;MESSAGE\aESC [
ESC ] 9 ; MESSAGE BELhex
1b 5d 39 3b ... 07说明
在系统托盘 / 通知中心 / KNotifications 中弹出一个包含指定消息字符串的桌面通知。最早源自 iTerm2 的 iTerm2 growl 机制(OSC 9 别名沿用自 macOS Growl 守护进程时代);Windows Terminal 后来也采用同一控制码。终端会把消息载荷转发到宿主 OS 通知 API —— 用户会在终端窗口之外看到横幅,常用于长编译、make && say done 的替代、CI 轮询。不支持的终端会静默丢弃整条 OSC 9,因此可安全地无条件发送。注意:ConEmu 将 OSC 9 重新定义为其进度条协议(\x1b]9;4;<state>;<percent>\x07),是另一套语义;发送复杂 OSC 9 载荷前请先查终端文档。
规范出处: iTerm2 Proprietary Escape Codes (OSC 9) / Windows Terminal
示例
make && printf '\033]9;build finished\007'import sys; sys.stdout.write('\x1b]9;build finished\x07')fmt.Print("\x1b]9;build finished\x07")process.stdout.write('\x1b]9;build finished\x07')printf("\x1b]9;build finished\x07");在哪里用到
实际会发出该序列的工具——把抽象字节锚定到你已经用过的命令上。
- make + iTerm2 build-done toast`make all && printf '\033]9;build finished\007' || printf '\033]9;BUILD FAILED\007'` 在长编译结束的瞬间弹出通知中心横幅 —— 开发者可以切走,仍能在 macOS 右上角一瞥结果
- WezTerm + Windows Terminal CI watchers长跑的 CI 轮询(`gh run watch`、`circleci-cli local execute --tail`)在状态转换时发 OSC 9 —— WezTerm 和 Windows Terminal 都转发到 Windows 通知中心 / Linux notify-osd;盯流水线的开发者无需额外装 `notify-send` 就拿到系统级提醒
- tmux pane-activity hooks通过 `set -g activity-action other` 加一小段包装,tmux 把内置的 `monitor-activity` 升级为真正的 OS 通知:包装在每次活动事件时发 `\x1b]9;activity in <pane>\x07`,多窗格工作会话即便无终端焦点也能提醒用户
- Ghostty + Konsole tail-watching scripts`tail -F deploy.log | grep --line-buffered ERROR | while read -r l; do printf '\033]9;%s\007' "$l"; done` 每出现错误就弹一条 Ghostty / KDE Plasma 通知 —— 比每行状态都唤醒更好,因为通知队列由 OS 限流而非终端
- ConEmu progress-bar variant (OSC 9;4 sub-protocol)ConEmu 用子语法 `\x1b]9;4;<state>;<percent>\x07` 劫持 OSC 9 来驱动 Windows 7 风格的任务栏进度条 —— `state=1` 正常,`2` 错误,`3` 不确定。现代 shell(PowerShell `oh-my-posh`、Bash `bash-completion`)在长文件操作中发出该序列,无需打印文本进度条即可显示进度
常见问题
针对这条序列,开发者真正会去搜索的问题的简短回答。
- 为什么 OSC 9 通知在 iTerm2 弹出,在 Windows Terminal 却被字面打出来?
- OSC 9 并非单一标准 —— 三个终端给
Ps=9槽位赋了不同用途。iTerm2 用\x1b]9;<message>\x07弹系统通知(调用 macOS Notification Center)。ConEmu / Windows Terminal 用\x1b]9;<state>;<value>\x07控制任务栏进度(状态 0–4:清除 / 正常 / 错误 / 不确定 / 暂停)。xterm 把 OSC 9 视为未定义并打出正文。要跨终端通知,请按终端分别发:iTerm2 用\x1b]9;text\x07,urxvt / KDE 用\x1b]777;notify;Title;Body\x07,kitty 0.31+ 用\x1b]99;i=<id>:p=body:;<text>\x1b\\。不存在单一通用通知转义。 - 如何检测当前终端讲的是哪种 OSC 9 方言?
- OSC 9 语义没有 DSR / DECRQM 探针 —— 字节槽共享,含义不一。用 XTVERSION
\x1b[>q拿终端名再分派:含iTerm2→ 通知方言;含ConEmu/ 设置了WT_SESSION环境变量 → 进度方言;含kitty→ 用 OSC 99(现代桌面通知规范);未知终端回退到notify-send/terminal-notifier。不要尝试通过发测试 OSC 9 来探测 —— 字面打出的终端即使包在 alt-screen 也会在滚动缓冲留下垃圾。
终端支持
- 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 不支持 | 不支持 | 不支持 | 支持 | 支持 | 不支持 | 不支持 | 不支持 | 支持 | 支持 | 不支持 | 部分 | 部分 | 不支持 |