先分别介绍一下我了解到 Mac 设置启动任务的方式:
1、进入系统偏好「设置」->「帐户」->「登陆项」
操作很简单,直接拖任务进去也可以,或点击底部的+
号添加即可。
2、利用/System/Library/StartupItems
和/Library/StartupItems/
配置文件
在这两个对应目录下,可以添加以下两种内容:可执行程序和StartupParameters.plist
文件(需要有权限)。
3、利用 Launchd 系统初始化进程配置
Launchd
是Mac
下用于初始化操作系统的关键进程。通过启动硬盘指定目录下的配置文件,来完成启动任务。这些文件为plist
,本质上是XML
。
Launchd 目录配置
Mac
下Launchd
的plist
文件放置的目录有:
~/Library/LaunchAgents 由用户自己定义的任务项
/Library/LaunchAgents 由管理员为用户定义的任务项
/Library/LaunchDaemons 由管理员定义的守护进程任务项
/System/Library/LaunchAgents 由Mac OS X为用户定义的任务项
/System/Library/LaunchDaemons 由Mac OS X定义的守护进程任务项
我们新写的建议放在~/Library/LaunchAgents
下面。
下面再来理解几个基础概念:
/System/Library和/Library和~/Library目录的区别?
/System/Library 目录是存放Apple自己开发的软件。
/Library 目录是系统管理员存放的第三方软件。
~/Library/ 是用户自己存放的第三方软件。
LaunchDaemons和LaunchAgents的区别?
LaunchDaemons 是用户未登陆前就启动的服务(守护进程)。
LaunchAgents 是用户登陆后启动的服务(守护进程)。
Launchd plist 配置
这里列举几个比较有用的配置关键字:
标签 | 必填 | 说明 |
---|---|---|
Label | 是 | 标识符,用来表示该任务的唯一性 |
Program | 是 | 程序名称,用来说明运行哪个程序、脚本 |
ProgramArguments | 是 | 同上,与Program二选一或一起使用,只是可以运行多个程序、可带参数 |
WatchPaths | 否 | 监控路径,当路径文件有变化是运行程序,也是数组 |
RunAtLoad | 否 | 是否在加载的同时启动 |
StartCalendarInterval | 否 | 运行的时间,单个时间点使用dict,多个时间点使用 array -> dict |
StartInterval | 否 | 时间间隔,与StartCalendarInterval使用其一,单位为秒 |
StandardInPath、StandardOutPath、StandardErrorPath | 否 | 标准的输入输出错误文件,这里建议不要使用.log 作为后缀,会打不开里面的信息 |
Launchd 使用案例
两种指定要执行命令的方法:
- 使用Program和ProgramArguments
Program, 运行命令或要执行文件路径
ProgramArguments, 执行时传入参数
- 只使用ProgramArguments
此时,ProgramArguments的每个参数为要执行的命令或文件路径,其它参数为传入参数
两种设置执行时间的方法:
- StartCalendarInterval
使用元素Minute, Hour, Day, Month, Weekday指定执行时间,如:
<!-- 每天的9:30执行 -->
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>30</integer>
<key>Hour</key>
<integer>9</integer>
</dict>
- StartInterval
设置执行的时间间隔,单位为秒,如:
<!-- 每小时执行一次 -->
<key>StartInterval</key>
<integer>3600</integer>
Launchd 定时任务
1.编写shell脚本文件
这里我们在~/Library/LaunchAgents
下新建一个文件test.sh
文件,写入要执行的内容,比如:
#!/bin/bash
say hello world
echo "out: 茶豆网:https://chadou.me"
上面的脚本会让电脑发声“hello world”,记得打开电脑音量哟!
注意:
你需要将test.sh
修改为可执行文件,否则,脚本无法执行。执行命令并查看test.sh是否可执行(拥有3个x权限),如下:
$ chmod a+x test.sh
$ ls -l
-rwxr-xr-x 1 david staff 86 1 31 17:10 test.sh
2.编写plist文件
这里我们在~/Library/LaunchAgents
下新建一个me.chadou.test.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>
<key>Label</key>
<string>me.chadou.test</string>
<key>ProgramArguments</key>
<array>
<string>/Users/david/Library/LaunchAgents/test.sh</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
然后,使用plutil
命令来验证plist的格式是否正确(无法验证命令有效性),如下:
$ plutil -lint me.chadou.test.plist
me.chadou.test.plist: OK
3.加载命令
使用launchctl
命令加载plist文件,launchctl
是一个统一的服务管理框架,启动、停止和管理守护进程、应用程序、进程和脚本。具体参数如下:
# 加载任务, -w选项会将plist文件中无效的key覆盖掉,建议加上
$ launchctl load -w me.chadou.test.plist
$ launchctl start me.chadou.test.plist
# 删除任务
$ launchctl stop me.chadou.test.plist
$ launchctl unload -w me.chadou.test.plist
# 查看任务列表, 使用 grep '任务部分名字' 过滤
$ launchctl list | grep 'me.chadou.test'
其他说明:
- 如果执行
launchctl load
命令出现me.chadou.test.plist: Path had bad ownership/permissions
,需要为plist文件赋予600
权限,执行下面命令:
sudo chmod 600 me.chadou.test.plist
- 如何执行
launchctl list
命令出现错误的代码,则需要仔细检查shell脚本内容。
$ launchctl list | grep 'me.chadou.test'
- 78 com.applefs.user # 错误结果
- 0 com.applefs.user # 正确结果
- shell脚本输出如果有中文,中文部分乱码,则需要在shell脚本中指定编码,如下:
#!/bin/bash
LANG=en_US.UTF-8
export LANG
echo "out: 茶豆网:https://chadou.me"