LaunchAgent 是 macOS 自带的任务调度机制(基于 launchd),适合在“当前用户”登录后运行:比如定时清理下载目录、同步某个文件夹、每天自动备份配置、定时跑一段脚本生成报表等。它的优点是系统原生、稳定、可控;缺点是配置相对偏底层,需要写一个 plist。
如果你的任务必须在未登录状态运行或需要系统级权限,通常应该用 LaunchDaemon(本文不展开,以免误操作影响系统)。
建议把脚本放到自己的家目录,比如 ~/ s,并确保它可执行:
mkdir -p ~/ s
chmod +x ~/ s/demo.sh
示例脚本(把输出追加到日志,便于确认任务是否在跑):
#!/bin/zsh echo "$(date) demo run" >> "$HOME/Library/Logs/demo-launchagent.log"
LaunchAgent 的配置文件一般放在:
~/Library/LaunchAgents/
创建一个文件,例如:
~/Library/LaunchAgents/com.example.demo.plist
一个最小可用的模板如下(把 ProgramArguments 指向你的脚本路径):
Label com.example.demo ProgramArguments /bin/zsh -lc $HOME/ s/demo.sh StartInterval 300 RunAtLoad StandardOutPath $HOME/Library/Logs/com.example.demo.out.log StandardErrorPath $HOME/Library/Logs/com.example.demo.err.log
说明:
1) StartInterval 是“每隔多少秒运行一次”(示例为 300 秒=5 分钟)。
2) RunAtLoad 会在加载任务时立即跑一次,便于验证。
3) 通过 StandardOutPath/StandardErrorPath 把输出落到日志文件,排错非常省心。
先确保目录存在:
mkdir -p ~/Library/LaunchAgents
加载(推荐 bootstrap 方式):
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.demo.plist
如果已加载过,需要先卸载再加载:
launchctl bootout gui/$(id -u) com.example.demo
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.demo.plist
查看任务是否存在:
launchctl list | grep com.example.demo
手动触发一次(不等计时器):
launchctl kickstart -k gui/$(id -u)/com.example.demo
优先看你在 plist 里写的标准输出/错误日志:
tail -n 50 ~/Library/Logs/com.example.demo.out.log
tail -n 50 ~/Library/Logs/com.example.demo.err.log
常见坑:
1) 路径问题:尽量在 plist 里写绝对路径,或用 /bin/zsh -lc 让 shell 解析 $HOME。
2) 权限问题:脚本必须可执行;如果脚本访问“桌面/文档/下载”等受保护目录,可能需要在“系统设置 -> 隐私与安全性”里给终端/脚本执行器授权。
3) 环境变量不同:LaunchAgent 的 PATH 往往更干净,脚本里用到的命令建议写绝对路径(例如 /usr/bin/python3),或者在脚本开头显式设置 PATH。
不需要时,先卸载:
launchctl bootout gui/$(id -u) com.example.demo
再删除 plist:
rm ~/Library/LaunchAgents/com.example.demo.plist
Apple 官方文档(System Startup / launchd jobs):https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
launchd/launchctl 资料站:https://www.launchd.info/