下面的介绍以该目标为例:
设置每天早上
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
:Minute
The minute on which this job will be run.Hour
The hour on which this job will be run.Day
The day on which this job will be run.Weekday
The weekday on which this job will be run (0 and 7 are Sunday).Month
The 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
的方式配置上比较简单,但调试起来比较麻烦。特别是出错时很难去定位。