coproc总线适合单机Bash脚本间低延迟通信:同主机、低吞吐、无持久化需求;用命名协进程+bus_send/bus_recv封装,需手动管理fd和优雅退出,不适用于跨主机或高可靠场景。

用 Bash 的 coproc 构建微型消息总线,不追求企业级功能,而是解决小规模脚本间低延迟、低开销的实时通信问题——比如监控脚本向告警脚本推送状态变更,或配置热更新通知。它本质是利用协进程维持一个常驻的、双向可读写的通信通道,比反复启停进程、轮询文件或用 netcat 建 TCP 更轻、更可控。
明确适用边界:什么场景适合,什么不该用
coproc 总线适合以下情况:
- 全部组件都在同一台 Linux 主机上,且由 Bash 或能操作文件描述符的程序(如 Python、awk)驱动
- 消息吞吐不高(每秒几十到几百条),单条消息不大于几 KB,不要求持久化或重试
- 需要快速原型验证、运维胶水脚本联动,或嵌入已有 shell 工程中,不想引入额外服务(如 Redis、D-Bus)
- 开发者熟悉 Bash 文件描述符操作,能接受手动管理管道生命周期
不适合替代消息中间件:无队列缓冲、无多消费者广播、无权限控制、崩溃即断连、不跨主机。
核心结构:一个命名协进程 + 两个封装函数
关键不是写死命令,而是把协进程变成“总线服务端”,再提供统一的 bus_send 和 bus_recv 接口:
- 用
coproc BUS { while IFS= read -r line; do echo "[$(date +%T)] $line" >&3; done } 3>&1启动命名协进程,标准输出重定向到 fd 3,供外部读取 -
bus_send()函数:向BUS[1]写入字符串,自动加换行 -
bus_recv()函数:从BUS[0]非阻塞读一行(可用read -t 0.1控制超时),避免卡住 - 所有参与脚本 source 同一份 bus.sh,共享
BUS数组变量(需在同一个 shell 会话或用export -f导出函数)
实操示例:日志采集器与阈值检查器联动
假设你有一个采集 CPU 使用率的后台循环,另一个脚本实时判断是否超限并触发动作:
- 采集脚本定期执行
top -bn1 | grep '%Cpu' | awk '{print $2}',得到数值后调用bus_send "cpu:$value" - 检查脚本持续调用
bus_recv,匹配cpu:(\d+\.?\d*),若 >85 则发邮件或写告警文件 - 两者无需知道对方 PID,也不依赖临时文件或信号,靠协进程管道天然同步
- 协进程本身可加简单路由逻辑,例如识别前缀
log:、config:,分发到不同处理分支
必须注意的细节和避坑点
coproc 看似简单,但几个关键细节决定是否稳定可用:
- 务必在脚本退出前显式关闭文件描述符:
exec {BUS[0]}>&-; exec {BUS[1]}>&-,否则子 shell 残留导致 fd 耗尽 - 协进程不能直接捕获 SIGINT;如需优雅退出,改用
kill $BUS_PID并等待wait $BUS_PID 2>/dev/null - 协进程内避免阻塞操作(如无超时的
read),否则整个总线卡死;推荐用read -t 0.05循环轮询 - 消息内容需自行约定格式(如 JSON 片段、key:value、空格分隔),协进程不解析,只透传;建议加简单校验(如长度限制、基础字段存在性)
- 多个脚本并发写入
BUS[1]是安全的(内核保证 write 原子性),但读取端需自己做去重或节流,避免雪崩


















