跳到主要内容
ansicode

OSC 9 — 桌面通知(iTerm2 / Windows Terminal)

从终端触发原生桌面通知 —— 长任务完成、构建结束等场景。

字节形式

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

\\x1b[\x1b]9;MESSAGE\x07
\\033[\033]9;MESSAGE\007
\\e[\e]9;MESSAGE\a
ESC [ESC ] 9 ; MESSAGE BEL
hex1b 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

示例

bash
make && printf '\033]9;build finished\007'
python
import sys; sys.stdout.write('\x1b]9;build finished\x07')
go
fmt.Print("\x1b]9;build finished\x07")
javascript
process.stdout.write('\x1b]9;build finished\x07')
c
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
不支持

相关序列

在家族食谱中

OSC 食谱 · 6. 内联图片与进度 —— `OSC 1337` 与 `OSC 9 ; 4`