终端里的长命令跑完了,让它通知你

别再守着一个跑四十分钟的构建。在任意命令后面加一行,结果就会送到手机上——包括你早就走开的那种情况。

更新于

目录

你启动了一次训练、一整套测试、一个 docker build,或者一个 AI 编程助手去处理一项耗时的任务。然后你只有两个糟糕的选项:坐着盯进度条,或者走开二十分钟回来发现它在第九十秒就失败了。

其实还有第三个选项,一行就够。

那一行

在 Echobell 里建一个频道,复制它的 webhook URL,然后接在你要跑的命令后面:

pnpm build; curl -sS -X POST https://hook.echobell.one/t/YOUR_TOKEN \
  -H 'content-type: application/json' \
  -d '{"title":"构建结束","body":"echobell-web"}'

注意这里是 ; 而不是 &&。用 && 的话,只有命令成功时才会发通知——而这恰好是反的:失败才是你最想知道的那种情况。

把退出码也带上

一条只说「结束了」的通知只讲了一半。把状态一起捕获:

pnpm build; s=$?; curl -sS -X POST https://hook.echobell.one/t/YOUR_TOKEN \
  -H 'content-type: application/json' \
  -d "{\"title\":\"构建 $([ $s -eq 0 ] && echo 成功 || echo 失败)\",\"status\":\"$s\"}"

s=$? 必须紧跟在命令后面。中间夹任何东西——包括 [ 这个测试命令本身——都会把 $? 覆盖掉。

做成一个 shell 函数

每次都手打这一串就失去意义了。把这个放进 ~/.zshrc~/.bashrc

notify() {
  "$@"
  local status=$?
  curl -sS -X POST "$ECHOBELL_HOOK" \
    -H 'content-type: application/json' \
    -d "{\"command\":\"$*\",\"status\":\"$status\",\"host\":\"$(hostname -s)\"}" \
    >/dev/null
  return $status
}

在 shell 配置里设置 ECHOBELL_HOOK——更好的做法是别把它放进会提交的 dotfiles 仓库,而是从一个不纳入版本控制的文件里 export。然后:

notify pnpm test
notify cargo build --release
notify python train.py

结尾那句 return $status 很重要:它让 notify 保持透明,所以 notify make && ./deploy.sh 依然按你预期的方式工作。

配合上面的 payload,频道模板可以写成:

标题

{{command}} · {{status}}

正文

在 {{host}} 上

只有失败时才叫我

大多数运行都会成功,你并不需要听到它们。用两个频道能干净地解决:一个普通频道收全部,一个来电频道加条件:

status != "0"

把值得你从床上爬起来的那些任务指向第二个频道,成功的运行就安静地过去了。

让它扛得住合上笔记本和断掉的 SSH

如果命令跑在 SSH 上,合上笔记本会杀掉这个 shell,通知也就永远不会发出去。两种解法:

tmux —— 在会话里启动然后 detach:

tmux new -d -s build 'notify pnpm build'

nohup —— 临时跑一次:

nohup bash -c 'notify pnpm build' >/dev/null 2>&1 &

两种方式都能让进程活过你的连接,通知会照常送达,不管你还连着没有。

AI 编程助手

同样的模式也适用于一个在处理长任务的 CLI 助手:

notify codex exec "重构支付模块并跑一遍测试"

至于那些跑到一半停下来等人的助手——比如需要审批、需要授权确认——完成通知是错的工具,因为它根本还没完成。那种情况需要的是助手自己的 hook 或回调,而且值得一通电话而不是一条推送。把 AI 助手的审批卡点变成一通电话专门讲了这件事,包括 Claude Code 的 Notification hook 和它的 agent_needs_input matcher。

两个都用:hook 负责「我卡住了」,shell 函数负责「我干完了」。

别往通知里放什么

别放命令输出。 把失败构建的最后几行塞进正文很有诱惑力,但请忍住——构建日志里出现 token、连接串和客户数据的频率比大多数人以为的高,而通知正文最终会显示在锁屏上。发退出码就够了,然后自己回终端看。

别把频道 URL 放进公开的 dotfiles 仓库。 拿到这个 URL 的人都能往你的频道发消息。把它放在不纳入版本控制的文件里,并打开 仅 POST,这样一个随手的链接预览也没法触发它。

常见问题

为什么不用 terminal-notifiernotify-send

那些是在跑命令的那台机器上弹通知。你人在跟前时它们没问题。这套方案针对的正是你不在跟前的情况——远程机器、合上的笔记本、另一个房间。

Windows 上能用吗?

模式一样,语法不同。PowerShell 里等价写法是 Invoke-RestMethod -Method Post -Uri $env:ECHOBELL_HOOK -ContentType application/json -Body $json,用 $LASTEXITCODE 代替 $?

能推到手表上吗?

可以。订阅会送达配对的 Apple Watch,而「构建好了」这件事,手表其实是最合适的形态。

如果命令要跑 12 个小时呢?

这套方案里没有任何超时——命令什么时候返回,curl 就什么时候执行。用 tmux 跑,免得连接断了把进程一起带走。

队友能收到同样的通知吗?

可以。把频道分享出去,每个订阅者自己选通知类型。共用一台训练机的时候很有用,不止一个人关心 GPU 什么时候空出来。

小结

一个 shell 函数、一个频道,只想要失败通知的话再加一个条件。设置大概花两分钟,换回你盯进度条的那二十分钟。

下载 iPhone 版 Echobell在 Google Play 获取,然后找一个长到值得你走开的任务试一次。


相关内容