cron + curl 是最稳的定时推消息组合:cron 负责准时唤醒,curl 负责发请求;需用绝对路径调用、设置 LANG 防乱码、Webhook 通过环境变量加载,企业微信/飞书推送须严格处理 JSON 格式、引号嵌套与空白字符,并通过工作日清单规避调休误发。

crontab + curl 是最稳的组合
Linux 上定时推消息,别想复杂——cron 负责准时唤醒,curl 负责发请求,两者合体就能跑通 95% 的日常场景。不需要常驻进程、不依赖 Python 环境、不担心脚本崩溃后没人拉起来。
关键不是“能不能做”,而是“怎么避免一上线就失败”。常见卡点有三个:cron 环境变量缺失、中文乱码、Webhook 地址硬编码泄露。
- 必须用绝对路径调用
/bin/bash或/usr/bin/curl,不能只写bash或curl - 脚本开头加
export LANG=en_US.UTF-8(或zh_CN.UTF-8),否则中文显示为问号或空格被截断 -
webhook URL别直接写死在脚本里;改用环境变量或外部配置文件,再用source加载
企业微信推送脚本要绕开两个坑
企业微信对 Content-Type 和 JSON 格式敏感,curl 少一个引号或换行符错位,返回 {"errcode":40071,"errmsg":"invalid json"} 是常态。
正确写法核心就三点:单引号包住整个 -d 参数、JSON 内部用双引号、日期等动态内容用 $(date ...) 插入且不破坏引号结构。
#!/bin/bash
export LANG=zh_CN.UTF-8
WEBHOOK="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx"
curl -s -X POST "$WEBHOOK"
-H 'Content-Type: application/json'
-d '{
"msgtype": "text",
"text": {
"content": "? '"$(date '+%Y-%m-%d %H:%M')"' —— 系统巡检完成
✅ CPU 使用率: 23%
✅ 磁盘剩余: 64%",
"mentioned_list": ["@all"]
}
}'- 注意
'? '"$(date ...)"' —— '这种拼接方式:外层单引号 + 中间双引号包裹的命令替换 + 外层继续单引号,才能让date正确展开又不破坏 JSON 结构 -
mentioned_list用["@all"]可全员提醒,但企业微信外部群不支持该字段,会静默忽略 - 如果提示
errcode: 40097,说明key错了或机器人被禁用;errcode: 40001表示 URL 里 key 缺失或带了空格
飞书推送得处理换行和空格
飞书对消息体中换行符和连续空格更敏感。用 curl 直推时,若内容含
或多个空格,可能被截断或折叠成单空格——这不是 bug,是飞书服务端默认行为。
公众号运营:文章发布至草稿、样式封面、评论与用户管理、数据统计等。用户要求将 Markdown 发送到公众号草稿、查看阅读量统计或类似后台操作时,使用本技能。
解决办法不是改飞书,而是提前清理字符串。Shell 里用参数扩展最轻量:
msg="⚠️ 告警:磁盘使用率超 90%
时间:$(date '+%Y-%m-%d %H:%M')
节点:web-server-01"
# 压缩多余空白并转义换行
clean_msg=$(echo "$msg" | sed ':a;N;$!ba;s/
/\n/g' | sed 's/[[:space:]]+/ /g' | sed 's/^ //;s/ $//')
curl -s -X POST "$FEISHU_WEBHOOK"
-H 'Content-Type: application/json'
-d "{"msg_type":"text","content":{"text":"$clean_msg"}}"- 飞书 Webhook 地址形如
https://open.feishu.cn/open-apis/bot/v2/hook/xxx,注意不是/bot/v2/hook/后面还有一串 token - 飞书不支持
@all,要用user_id或open_id显式 @ 成员,否则只能发给群全体(无高亮) - 如果脚本在 Windows 下编辑再传到 Linux,记得运行
sed -i 's/ $//' script.sh清除,否则 cron 会报/bin/bash^M: bad interpreter
工作日推送不能只靠 crontab * * * *
cron 的 5 9 * * 1-5 只能保证周一到周五,但遇上国庆调休、春节补班,它照发不误。真要按实际工作日推送,得自己判断今天是不是“该上班的日子”。
最简方案:维护一个纯文本工作日清单(如 /opt/workdays.txt),每行一个 YYYY-MM-DD,脚本启动时用 grep -q "$(date +%Y-%m-%d)" /opt/workdays.txt 判断。
- 清单可手动更新,也可对接公开节假日 API(如国务院每年发布的放假安排),但后者需额外加 HTTP 请求逻辑
- 别用
date -d "today +1 day"类推算,调休日无法规则化生成 - 如果 crontab 执行时发现非工作日,直接
exit 0即可,不用报错,避免塞满日志
真正麻烦的从来不是“怎么发”,而是“什么时候不该发”——那个被漏掉的调休日,往往就是凌晨三点收到消息后被骂醒的开始。


















