当你想让某个脚本在登录后自动运行、或按固定时间间隔执行(例如每 30 分钟跑一次同步、每天凌晨生成报告),macOS 的 launchd 是系统级的任务管理器。对个人工作流来说,使用 LaunchAgents(用户级)通常比 crontab 更稳:它跟随用户会话、权限更清晰,也更符合 macOS 的机制。
本文只讲合规、日常提效的定时/常驻任务;不涉及任何入侵、破解、绕过付费等内容。
用户级任务(推荐从这里开始):
~/Library/LaunchAgents/
系统级任务(需要更高权限,本文不展开):
/Library/LaunchDaemons/
建议规则:每个任务一个唯一的 Label(通常用反向域名风格),并把脚本放在你确定存在、权限正确的位置。
1)创建脚本(示例路径:~/ s/hello-launchd.sh):
#!/bin/zsh echo "[$(date)] launchd says hi" >> "$HOME/Library/Logs/hello-launchd.log"
别忘了给执行权限:
chmod +x ~/ s/hello-launchd.sh
2)创建 plist(示例路径:~/Library/LaunchAgents/com.example.hello-launchd.plist):
<? version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.example.hello-launchd</string> <key>ProgramArguments</key> <array> <string>/bin/zsh</string> <string>-lc</string> <string>$HOME/ s/hello-launchd.sh</string> </array> <key>StartInterval</key> <integer>1800</integer> <key>RunAtLoad</key> <true/> <key>StandardOutPath</key> <string>$HOME/Library/Logs/hello-launchd.out</string> <key>StandardErrorPath</key> <string>$HOME/Library/Logs/hello-launchd.err</string> </dict> </plist>
这个配置做了两件事:登录时立即跑一次(RunAtLoad),之后每 1800 秒跑一次(StartInterval)。输出/错误分别写到日志文件,方便排查。
加载(启用):
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.hello-launchd.plist
卸载(禁用):
launchctl bootout gui/$(id -u) com.example.hello-launchd
查看是否在跑(或是否报错):
launchctl print gui/$(id -u)/com.example.hello-launchd
查看输出日志:
tail -n 50 ~/Library/Logs/hello-launchd.out
1)路径一定写绝对路径:launchd 不会帮你补 PATH。尽量写成 /bin/zsh、/usr/bin/python3 这种绝对路径。
2)脚本要有执行权限:别忘了 chmod +x,否则任务会静默失败。
3)环境变量差异:在 Finder 双击能跑,不代表 launchd 也能跑。必要时用 -lc 让 shell 加载登录环境,或在脚本开头显式设置 PATH。
4)先把日志打出来:通过 StandardOutPath/StandardErrorPath 把日志落地,是最快的排错方式。
5)Label 唯一且稳定:改 Label 相当于新任务;排查时优先用 launchctl print 看当前状态与最后错误。
launchd 非官方速查(结构清晰,适合入门对照):https://www.launchd.info/
Apple 官方文档(launchd jobs 创建与概念):https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html