Mac LaunchAgent配置:兼顾全磁盘权限与caffeinate防睡眠
问题:如何配置LaunchAgent确保脚本运行期间电脑保持唤醒?
现有设置
- 目标:每天凌晨4点自动运行脚本,完成数据下载、模型拟合并保存文件。
- Shell脚本路径:
/Library/Scripts/myscript.sh,已设置执行权限,内容如下:
#!/bin/sh cd "/Users/myusername/Desktop/my/dir/with/data"; /opt/homebrew/bin/python3 download_data.py; /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/bin/Rscript fitModels.R;
- LaunchAgent配置文件路径:
~/Library/LaunchAgents/local.myscript.plist,已通过launchctl加载,使用fdautil赋予脚本全磁盘访问权限,内容如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>local.myscript</string> <key>ProgramArguments</key> <array> <string>/usr/local/bin/fdautil</string> <string>exec</string> <string>/Library/Scripts/myscript.sh</string> </array> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>4</integer> <key>Minute</key> <integer>0</integer> </dict> </dict> </plist>
- 已设置电脑凌晨3:58自动唤醒,脚本可正常启动,但运行几分钟后电脑会进入睡眠,导致脚本无法完成。
已尝试的方案及问题
- 将
caffeinate作为plist的第一个ProgramArgument:fdautil失效,Python和R脚本因权限问题无法执行。 - 将
/usr/bin/caffeinate放在fdautil exec之后作为第三个参数:提示You don't have permission to run this command via fdautil。 - 在Shell脚本每行命令前添加
caffeinate:Python部分正常运行,但R脚本加载包时被杀死,提示zsh: killed caffeinate fitModels.R(无caffeinate时R脚本可正常运行)。 - 替代方案:单独创建LaunchAgent调用
caffeinate -t并设置足够长的时长,但脚本每日运行时长差异大,该方案不够优雅。
解决方案
方法1:在Shell脚本内用caffeinate包裹整个执行逻辑
修改myscript.sh,让caffeinate在脚本运行期间保持电脑唤醒,直到所有任务完成:
#!/bin/sh # 使用caffeinate -s 阻止系统睡眠,直到内部命令执行完毕 caffeinate -s sh -c ' cd "/Users/myusername/Desktop/my/dir/with/data" /opt/homebrew/bin/python3 download_data.py # 检查Python脚本执行状态,失败则直接退出 if [ $? -ne 0 ]; then exit 1 fi /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/bin/Rscript fitModels.R '
-s参数:阻止系统进入睡眠状态,直到caffeinate的子进程(即包裹的命令)结束。- 这种方式不会影响
fdautil的权限传递,因为caffeinate是在脚本内部执行,而非通过fdautil直接调用。
方法2:为脚本添加独立的caffeinate守护进程
如果方法1中R脚本仍有问题,可以尝试在脚本启动时单独启动caffeinate,任务完成后再终止它:
#!/bin/sh # 启动caffeinate并后台运行,记录PID caffeinate -s & CAFFEINATE_PID=$! # 执行核心任务 cd "/Users/myusername/Desktop/my/dir/with/data" /opt/homebrew/bin/python3 download_data.py PYTHON_EXIT=$? if [ $PYTHON_EXIT -eq 0 ]; then /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/bin/Rscript fitModels.R R_EXIT=$? else R_EXIT=$PYTHON_EXIT fi # 任务完成后终止caffeinate kill $CAFFEINATE_PID exit $R_EXIT
额外优化:在LaunchAgent中添加日志输出
为了排查问题,可以在plist中添加日志相关配置,方便查看脚本执行状态:
<key>StandardOutPath</key> <string>/Users/myusername/Library/Logs/myscript_stdout.log</string> <key>StandardErrorPath</key> <string>/Users/myusername/Library/Logs/myscript_stderr.log</string>
添加后重新加载plist:
launchctl unload ~/Library/LaunchAgents/local.myscript.plist launchctl load ~/Library/LaunchAgents/local.myscript.plist
内容的提问来源于stack exchange,提问作者Ike348
相关产品推荐
相关产品推荐

