macOS 使用 launchctl 和 crontab 设置定时任务的方法
- 电脑基础
- 2023-11-19
- 4458热度
- 0评论
下面的介绍以该目标为例:
设置每天早上
9点定时执行/Users/lzwme/schedule/helloworld.cjs的Node.js程序。
日志记录目录: /Users/lzwme/schedule/logs
1 基于 launchctl 设置定时任务
launchctl 是一个统一的服务管理框架,可以启动、停止和管理守护进程、应用程序、进程和脚本等。
launchctl 是通过配置文件来指定执行周期和任务的。
1.1 创建 run.sh 脚本
执行 vi /Users/lzwme/schedule/run.sh,然后参考输入如下内容:
#!/bin/sh
# 默认不会加载环境变量。主动加载一下
source ~/.bashrc_profile
# 加载 homebrew 环境变量
export PATH=/opt/homebrew/bin:$PATH
# 这里使用了 fnm 管理 node.js 版本,主动加载 fnm bin 所在目录到PATH环境变量
# 注意修改为你的需要设置,并修改实际的安装路径
export PATH=/Users/lzwme/Library/Caches/fnm_multishells/1295_1704804685161/bin:$PATH
# 记录一下开始时间
date
# 进入helloworld.cjs程序所在目录
cd /Users/lzwme/schedule
# 执行 helloworld.cjs 程序
node helloworld.cjs
# 运行完成
echo 'end'
保存退出后,然后为脚本设置可执行权限:
chmod 777 /Users/lzwme/schedule/run.sh
1.2 编写 plist 文件
launchctl 根据 plist 文件的信息来启动任务。plist 脚本一般存放在以下目录:
/Library/LaunchDaemons只要系统启动了都会执行,即使用户没有登录/Library/LaunchAgents当用户登陆系统后才会被执行
更多的 plist 存放目录:
~/Library/LaunchAgents由用户自己定义的任务项/Library/LaunchAgents由管理员为用户定义的任务项/Library/LaunchDaemons由管理员定义的守护进程任务项/System/Library/LaunchAgents由Mac OS X为用户定义的任务项/System/Library/LaunchDaemons由Mac OS X定义的守护进程任务项
我们这里进入 ~/Library/LaunchAgents,创建一个 plist 文件 com.lzw.me.plist,内容参考:
<?xml 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>
<!-- Label唯一的标识 -->
<key>Label</key>
<string>com.lzw.me.plist</string>
<!-- 是否加载时立即执行 -->
<key>RunAtLoad</key>
<false/>
<!-- 命令语句,指定要运行的脚本 -->
<key>ProgramArguments</key>
<array>
<string>/Users/lzwme/run.sh</string>
</array>
<!-- 指定要运行的时间 -->
<key>StartCalendarInterval</key>
<array>
<dict>
<!-- 指定每天9:00执行 -->
<key>Hour</key>
<integer>09</integer>
<key>Minute</key>
<integer>00</integer>
</dict>
<dict>
<!-- 指定周日 17:00 也执行一次 -->
<key>Weekday</key>
<integer>0</integer>
<key>Hour</key>
<integer>17</integer>
<key>Minute</key>
<string>00</string>
</dict>
</array>
<!-- 标准输出文件 -->
<key>StandardOutPath</key>
<string>/Users/lzwme/schedule/logs/run.log</string>
<!-- 标准错误输出文件,错误日志 -->
<key>StandardErrorPath</key>
<string>/Users/lzwme/schedule/logs/run.err.log</string>
</dict>
</plist>
关于 plist 文件的配置
plist 支持两种方式配置执行时间:
StartInterval: 指定每间隔多长时间(单位秒)执行一次StartCalendarInterval: 指定脚本在多少分钟、小时、天、星期几、月时间上执行,类似crontab的设置,包含以下key:MinuteThe minute on which this job will be run.HourThe hour on which this job will be run.DayThe day on which this job will be run.WeekdayThe weekday on which this job will be run (0 and 7 are Sunday).MonthThe month on which this job will be run.
plist 部分参数说明:
Label:对应的需要保证全局唯一性Program:要运行的程序ProgramArguments:命令语句StartCalendarInterval:运行的时间,单个时间点使用dict,多个时间点使用 arrayStartInterval:时间间隔,与StartCalendarInterval使用其一,单位为秒StandardInPath、StandardOutPath、StandardErrorPath:标准的输入输出错误文件。- 定时启动任务时如果涉及到网络,但是电脑处于睡眠状态则执行不了。可以定时的启动屏幕。
1.3 加载命令
launchctl load -w com.lzw.me.plist
这样任务就加载成功了。
更多的命令:
# 加载任务, -w选项会将plist文件中无效的key覆盖掉,建议加上
$ launchctl load -w com.lzw.me.plist
# 删除任务
$ launchctl unload -w com.lzw.me.plist
# 查看任务列表, 使用 grep '任务部分名字' 过滤
$ launchctl list | grep 'com.lzw.me'
# 查看出错信息。`launchctl list` 的第一列为错误码,若不为 0 则表示出错
$ launchctl error [error_code]
# 开始任务
$ launchctl start com.lzw.me.plist
# 结束任务
$ launchctl stop com.lzw.me.plist
说明:
- 若修改了任务,需先
unload再load才能生效:launchctl unload -w com.lzw.me.plist && launchctl load -w com.lzw.me.plist start可以立即执行任务,以方便测试。这点比 crontab 方便(若修改了任务,仍需先unload && load)- 执行
start和unload前,任务必须先load以加载任务 stop可以停止任务,而无需删除文件
2 MacOS 基于 crontab 设置定时任务
crontab 是一个 Linux 类系统通用的命令行工具,用于设置周期性执行的定时任务。在 MacOS 中,crontab 命令的用法与 Linux 基本一致。但它在 MacOS 上的执行,也是基于 launchctl 和 plist 文件实现的自启动。
2.1 配置 crontab 程序
首先使用 launchctl 查看crontab 程序的启动配置是否已存在:
sudo launchctl list | grep cron
有输出则说明任务存在
然后执行命令查看启动项配置:locate com.vix.cron
若有报错输出,则按提示操作即可。一般未曾操作过,会提示你执行如下命令以加载 locate 文件。执行它即可:
sudo launchctl load -W /System/Library/LaunchDaemons/com.apple.locate.plist
查看 /etc/crontab 文件是否存在,若不存在则创建:
ls /etc/crontab
sudo touch /etc/crontab
2.2 为 cron 程序添加完全磁盘访问权限
OSX 10.15 以上版本,需要为 cron 程序添加完全磁盘访问权限,否则会报错。具体方法为:
执行如下命令,打开 cron 程序所在目录:
# 查看 cron 位置。一般会输出: /usr/sbin/cron
which cron
# 打开该目录
open /usr/sbin
接着依次打开: 系统偏好设置 -> 安全性与隐私 -> 隐私 -> 完全磁盘访问权限。将 /usr/sbin 下的 cron 程序拖动到这里。
2.3 配置定时任务
接下来的操作,就和 Linux 基本一致了。
首先,执行命令添加定时任务:crontab -e
在打开的编辑器中输入任务配置。以上面的目标为例,输入如下内容:
0 09 * * * /Users/lzwme/schedule/run.sh >> /Users/lzwme/schedule/logs/run.log 2>&1;
crontab -l查看已设置的定时任务crontab -r删除所有定时任务
3 总结与参考
launchctl 是系统级别的工具,可以实现各种需求的实现。但基于 plist 文件的方式相对复杂一些。好处是可以使用 start 命令即时调试,出错时可以很方便的定位。
crontab 的方式配置上比较简单,但调试起来比较麻烦。特别是出错时很难去定位。