Mac 有兩種方式可以添加定時任務:
- crontab 命令
- launchctl 定時任務
crontab 命令
通過crontab 命令,我們可以在固定的間隔時間執行指定的系統指令或 shell script腳本。時間間隔的單位可以是分鐘、小時、日、月、周及以上的任意組合。這個命令非常適合週期性的日誌分析或數據備份等工作。
命令格式
crontab [-u user] file
crontab [-u user] [ -e | -l | -r ]
- -u user:用來設定某個用戶的crontab服務;
- file:file是命令文件的名字,表示將file做爲crontab的任務列表文件並載入crontab。如果在命令行中沒有指定這個文件,crontab命令將接受標準輸入(鍵盤)上鍵入的命令,並將它們載入crontab。
- -e:編輯某個用戶的crontab文件內容。如果不指定用戶,則表示編輯當前用戶的crontab文件。
- -l:顯示某個用戶的crontab文件內容,如果不指定用戶,則表示顯示當前用戶的crontab文件內容。
- -r:從/var/spool/cron目錄中刪除某個用戶的crontab文件,如果不指定用戶,則默認刪除當前用戶的crontab文件。
- -i:在刪除用戶的crontab文件時給確認提示。
crontab 文件格式
分 時 日 月 星期 要運行的命令
- 第1列分鐘1~59
- 第2列小時1~23(0表示子夜)
- 第3列日1~31
- 第4列月1~12
- 第5列星期0~7(0和7表示星期天)
- 第6列要運行的命令
備份/恢復 crontab
可以定時備份 crontab 以防誤刪操作
# 備份
crontab -l > $HOME/.mycron
# 恢復
crontab $HOME/.mycron
定時實例
# 每1分鐘執行一次myCommand
* * * * * myCommand
# 每小時的第3和第15分鐘執行
3,15 * * * * myCommand
# 在上午8點到11點的第3和第15分鐘執行
3,15 8-11 * * * myCommand
# 每隔兩天的上午8點到11點的第3和第15分鐘執行
3,15 8-11 */2 * * myCommand
# 每週一上午8點到11點的第3和第15分鐘執行
3,15 8-11 * * 1 myCommand
# 晚上11點到早上7點之間,每隔一小時重啓smb
* 23-7/1 * * * /etc/init.d/smb restart
注意清理系統用戶的郵件日誌
每條任務調度執行完畢,系統都會將任務輸出信息通過電子郵件的形式發送給當前系統用戶,這樣日積月累,日誌信息會非常大,可能會影響系統的正常運行,因此,將每條任務進行重定向處理非常重要。 例如,可以在crontab文件中設置如下形式,忽略日誌輸出:
0 */3 * * * /usr/local/apache2/apachectl restart >/dev/null 2>&1
launchctl 定時任務
下面將手把手教你在mac上創建定時任務。(任務目標:每天晚上十點定時執行/Users/demo/helloworld.py的python程序)
1. 創建run.sh腳本
進入 helloworld.py
程序所在目錄cd /User/demo
創建run.sh腳本vi run.sh
添加執行helloworld.py
的命令
#!/bin/sh
# 記錄一下開始時間
echo `date` >> /Users/demo/log &&
# 進入helloworld.py程序所在目錄
cd /Users/demo &&
# 執行python腳本(注意前面要指定python運行環境/usr/bin/python,根據自己的情況改變)
/usr/bin/python helloworld.py
# 運行完成
echo 'finish' >> /Users/demo/log
:wq
保存退出
注意,腳本要改成可執行的權限chmod 777 run.sh
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.demo.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.demo.plist</string>
<!-- 指定要運行的腳本 -->
<key>ProgramArguments</key>
<array>
<string>/Users/demo/run.sh</string>
</array>
<!-- 指定要運行的時間 -->
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>00</integer>
<key>Hour</key>
<integer>22</integer>
</dict>
<!-- 標準輸出文件 -->
<key>StandardOutPath</key>
<string>/Users/demo/run.log</string>
<!-- 標準錯誤輸出文件,錯誤日誌 -->
<key>StandardErrorPath</key>
<string>/Users/demo/run.err</string>
</dict>
</plist>
launchctl 通過配置文件指定執行週期和任務,不同於 crontab,launchctl 的最小時間間隔是 1s。
plist 文件存放路徑爲/Library/LaunchAgents
或/Library/LaunchDaemons
,前者僅當用戶登陸後才被執行,後者只要系統啓動就會被執行。
支持兩種方式配置執行時間:
-
StartInterval: 指定腳本每間隔多長時間(單位:秒)執行一次;
-
StartCalendarInterval: 可以指定腳本在多少分鐘、小時、天、星期幾、月時間上執行,類似如crontab的中的設置,包含下面的 key:
Minute <integer> The minute on which this job will be run. Hour <integer> The hour on which this job will be run. Day <integer> The day on which this job will be run. Weekday <integer> The weekday on which this job will be run (0 and 7 are Sunday). Month <integer> The month on which this job will be run.
3. 加載命令
launchctl load -w com.demo.plist
這樣任務就加載成功了。 -
# 加載任務, -w選項會將plist文件中無效的key覆蓋掉,建議加上 $ launchctl load -w com.demo.plist # 刪除任務 $ launchctl unload -w com.demo.plist # 查看任務列表, 使用 grep '任務部分名字' 過濾 $ launchctl list | grep 'com.demo' # 開始任務 $ launchctl start com.demo.plist # 結束任務 $ launchctl stop com.demo.plist
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>com.uniflor.notifier</string> <!-- 要運行的程序, 如果省略這個選項,會把ProgramArguments的第一個 元素作爲要運行的程序 --> <key>Program</key> <string>/Users/uniflor/script.sh</string> <!-- 命令, 第一個爲命令,其它爲參數--> <key>ProgramArguments</key> <array> <string>/Users/uniflor/script.sh</string> </array> <!-- 運行時間 --> <key>StartCalendarInterval</key> <dict> <key>Minute</key> <integer>30</integer> <key>Hour</key> <integer>9</integer> <key>Day</key> <integer>1</integer> <key>Month</key> <integer>5</integer> <!-- 0和7都指星期天 --> <key>Weekday</key> <integer>0</integer> </dict> <!-- 運行間隔,與StartCalenderInterval使用其一,單位爲秒 --> <key>StartInterval</key> <integer>30</integer> <!-- 標準輸入文件 --> <key>StandardInPath</key> <string>/Users/uniflor/run-in.log</string> <!-- 標準輸出文件 --> <key>StandardOutPath</key> <string>/Users/uniflor/Bin/run-out.log</string> <!-- 標準錯誤輸出文件 --> <key>StandardErrorPath</key> <string>/Users/uniflor/Bin/run-err.log</string> </dict> </plist>
配置文件
進入到~/Library/LaunchAgents
下建一個plist文件com.test.launchctl.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>com.test.launchctl.plist</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python</string>
<string>/Workspace/test.py</string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>4</integer>
<key>Hour</key>
<integer>13</integer>
</dict>
<key>KeepAlive</key>
<false/>
<key>RunAtLoad</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/AutoMakeLog.log</string>
<key>StandardErrorPath</key>
<string>/tmp/AutoMakeLog.err</string>
</dict>
</plist>
- StartCalendarInterval: 執行週期
- RunAtLoad: 加載時執行一次
- StandardOutPath: 標準輸出路徑
- StandardErrorPath: 錯誤輸出路徑
管理定時任務
- 加載任務
cd ~/Library/LaunchAgents
launchctl load com.test.launchctl.plist
- 卸載任務
launchctl unload com.felink.gitmirror.plist
- 立即執行一次任務
launchctl start ccom.test.launchctl.plist
- 停止任務
launchctl stop ccom.test.launchctl.plist
寫個簡單的applescript。
on callmeican()
set meican_url to "https://meican.com" as string
tell application "Google Chrome"
open location meican_url
activate
end tell
end callmeican
say "不要這麼拼了,預訂美餐時間到了"
display dialog "不要這麼拼了,預訂美餐時間到了(截至時間16:30)!" buttons {"好的", "我不定了"} default button 1
if the button returned of the result is "好的" then
-- action for 1st button goes here
callmeican()
end if
腳本的作用大概是MAC會通過彈窗和語音提醒我該訂餐了,如果選擇定,就自動用瀏覽器打開訂餐的頁面。這個腳本每天在四點執行。
1、使用crontab設置定時任務
crontab -e 或者sudo crontab -e。
00 16 * * * osascript /Users/hanlingzhi/project/applescript/meican.scpt
輸入完成後,保存退出。系統自動建立新cron,提示如下:crontab: installing new crontab。設置非常簡單。
2、使用蘋果的Schedule jobs using launchd設置定時任務。需要寫一個plist文件,描述任務的動作、間隔的時間、日誌輸出等參數。
我創建一個plist文件com.hanlingzhi.cron.meican.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>com.hanlingzhi.cron.meican</string>
<!-- 命令, 第一個爲命令,其它爲參數-->
<key>ProgramArguments</key>
<array>
<string>osascript</string>
<string>/Users/hanlingzhi/project/applescript/meican.scpt</string>
</array>
<!-- 運行時間 -->
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>0</integer>
<key>Hour</key>
<integer>16</integer>
</dict>
<!-- 標準輸入文件 -->
<key>StandardInPath</key>
<string>/Users/hanlingzhi/project/applescript/log/run-in-meican.log</string>
<!-- 標準輸出文件 -->
<key>StandardOutPath</key>
<string>/Users/hanlingzhi/project/applescript/log/run-out-meican.log</string>
<!-- 標準錯誤輸出文件 -->
<key>StandardErrorPath</key>
<string>/Users/hanlingzhi/project/applescript/log/run-err-meican.log</string>
</dict>
</plist>
然後將plist文件放在/Users/hanlingzhi/Library/LaunchAgents,你的用戶目錄下,然後執行launchctl load plist就可以啓動了。
plist腳本存放路徑爲/Library/LaunchDaemons或用戶目錄/Library/LaunchAgents,其區別是後一個路徑的腳本當用戶登陸系統後纔會被執行,前一個只要系統啓動了,哪怕用戶不登陸系統也會被執行。
可以通過兩種方式來設置腳本的執行時間。一個是使用StartInterval,它指定腳本每間隔多長時間(單位:秒)執行一次;另外一個使用StartCalendarInterval,它可以指定腳本在多少分鐘、小時、天、星期幾、月時間上執行,類似如crontab的中的設置。
<key>StartInterval</key>
<integer>3600</integer>
或者
<key>StartCalendarInterval</key>
<dict>
<key>Minute</key>
<integer>30</integer>
<key>Hour</key>
<integer>9</integer>
</dict>
launchctl的命令使用大家看一下幫助文檔。
由於操作還是比較複雜,爲了幫助快速執行,寫了個shell快速拷貝新的plist並完成服務重啓
__path='/Users/hanlingzhi/project/applescript'
__plist_path=${__path}/plist
__launchagents_path='/Users/hanlingzhi/Library/LaunchAgents'
# 拷貝plist到用戶自己定義的任務項目錄
cp -rf ${__plist_path}/* ${__launchagents_path}
# 根據plist中的文件遍歷load
for plist_file in `ls ${__plist_path}`
do
echo "重啓${plist_file}定時任務"
launchctl unload ${__launchagents_path}/${plist_file}
sleep 0.5
launchctl load ${__launchagents_path}/${plist_file}
task_name=`echo ${plist_file} | sed 's/.plist//g'`
launchctl list | grep ${task_name}
done
總結一下
雖然plist的設置會複雜很多。但是當前在mac os還是傾向於推薦使用Plist的方法,crontab已不推薦使用。
兩者的區別:
1、plist可以設置到秒,而crontab只能到分鐘。
2、plist可以同時應用於Mac OS/Iphone。
3、plist對於MAC上系統交互的操作更支持(我就出現過用crontab設置,運行時出現execution error: 不允許用戶交互。 (-1713)的錯誤