UnixやUnix系OS (Linux) には、指定した日時や間隔でタスクやコマンド、スクリプトを自動で実行することができる cron という便利な機能が存在します。今回はそれの基本的な使い方を自分用の備忘録として書き残しておきます。
環境は Linux Mint 22 “Wilma” MATE Edition です。
cron 及び crontab の基礎知識
cronとは
cron (クロン or クローン) とは、指定した日時や間隔でタスクを自動的に実行するために用いられるツールです。
cron と crontab の違い
cron と crontab の違いは cron がタスクを自動化するためのツールなのに対し crontab は cron を制御するコマンドやタスクを実行する日時や間隔が記述されたファイルを指します。
crontabコマンドの基本的な使い方
crontabの設定を確認
$ crontab -l
crontabの設定を変更するたびに確認メッセージを出す
$ crontab -i
crontabの設定を編集
$ crontab -e
crontabの設定を削除
$ crontab -r
cronを使用する前に必ずやっておいた方が良いこと
crontab設定を編集するには、端末から crontab -e
を実行します。しかし [e] キーの隣に位置する [r] キーをタイプして誤って crontab -r
と実行してしまうと全てのcron設定が警告なしに削除されてしまい非常に危険です。このリスクを避けるために crontab -r
を実行すると毎回警告を出す設定に変更します。
まず、どのテキストエディタでも構わないので .bashrc を開きます。
$ nano ~/.bashrc
.bashrc の一番最後の行に以下を追記し、保存します。
alias crontab='crontab -i'
最後にエイリアスを有効化します。
$ source ~/.bashrc
最後に crontab -r
を実行して確認のメッセージが出ればOKです。
これでタイプミスによってcrontab設定が全て削除される危険性がずっと低くなりました。
crontab の書式
基本構文
crontabの基本的な構文は以下の通りです。
m h dom mon dow command (分 時 日 月 曜日 コマンド)
左から順に「分 (minute)」「時 (hour)」「日 (day of month)」「月 (month)」「曜日 (day of week)」を数字または文字列で指定し、一番右に実行するコマンドやスクリプトを記述します。
指定できる値と特殊文字
項目 | 指定できる値 | 指定できる特殊文字 |
分 | 0~59 | , - * / |
時 | 0~59 | , - * / |
日 | 0~59 | , - * / |
月 | 1~12 あるいは JAN~DEC | , - * / |
曜日 | 0~7 あるいは SUN~SAT | , - * / |
月や曜日の指定は数字のほか、特定の文字列でも指定できます。
月の指定に使える値と文字列 | 月 |
1 もしくは JAN | 1月 |
2 もしくは FEB | 2月 |
3 もしくは MAR | 3月 |
4 もしくは APR | 4月 |
5 もしくは MAY | 5月 |
6 もしくは JUN | 6月 |
7 もしくは JUL | 7月 |
8 もしくは AUG | 8月 |
9 もしくは SEP | 9月 |
10 もしくは OCT | 10月 |
11 もしくは NOV | 11月 |
12 もしくは DEC | 12月 |
一部のシステムでは、数字で日曜日を指定する場合 0 だけでなく 7 も使えます。
曜日の指定に使える値と文字列 | 曜日 |
0 もしくは SUN | 日曜日 |
1 もしくは MON | 月曜日 |
2 もしくは TUE | 火曜日 |
3 もしくは WED | 水曜日 |
4 もしくは THU | 木曜日 |
5 もしくは FRI | 金曜日 |
6 もしくは SAT | 土曜日 |
(7 もしくは SUN) | (日曜日) |
分単位での指定例
毎時25分に sample.sh を実行
25 * * * * bash sample.sh
時間単位での指定例
毎日午前4時0分に sample.sh を実行
0 4 * * * bash sample.sh
注意: この時「0」の代わりに「*
(アスタリスク)」を分に指定すると、毎日午前4時0分になったら1分ごとに sample.sh を実行する設定になってしまうので注意します。
### 以下の設定では「毎日午前4時0分になったら1分ごとに sample.sh を実行」になってしまう ###
* 4 * * * bash sample.sh
日単位での指定例
毎月20日の23時30分に sample.sh を実行
30 23 20 * * bash sample.sh
月単位での指定例
毎年10月10日の午前2時0分に sample.sh を実行
0 2 10 10 * bash sample.sh
曜日での指定例
毎週水曜日の18時45分に sample.sh を実行
45 18 * * 3 bash sample.sh
範囲で指定する
「-
(ハイフン)」で実行する時間の範囲を指定することができます。
毎週月曜日の18時15分、19時15分、20時15分、21時15分に sample.sh を実行
15 18-21 * * 1 bash sample.sh
複数の時間で指定する
「,
(カンマ)」で値を区切ることで、実行する時間を複数設定することが可能です。
毎週火曜日、木曜日、土曜日の20時30分に sample.sh を実行
30 20 * * 2,4,6 bash sample.sh
毎週月曜日の9時00分、12時00分、15時00分、18時00分に sample.sh を実行
0 9,12,15,18 * * 1 bash sample.sh
間隔で指定する
「/
(スラッシュ)」で実行する時間の間隔を指定できます。
20分ごとに sample.sh を実行
*/20 * * * * bash sample.sh
2時間ごとに sample.sh を実行
* */2 * * * bash sample.sh
10日ごとに sample.sh を実行
* * */10 * * bash sample.sh
範囲指定と間隔指定の組み合わせ
毎週月曜日の9時00分~18時00分まで3時間おきに sample.sh を実行
0 9-18/3 * * 1 bash sample.sh
その他
日時や曜日を全て * (アスタリスク)で指定すると、1分ごとにタスクを実行する設定になります。
### 毎分 sample.sh を実行 ###
* * * * * bash sample.sh
### 上記は以下と同じ ###
*/1 * * * * bash sample.sh
crontabを記述するにあたっての注意点
秒単位で指定することができない
cronの実行時間の最小単位は「分単位」なので、「秒単位」で指定したい場合は少し複雑になります。
15秒おきに sample.sh を実行
for、seq、sleep コマンドを組み合わせて実現しています。
* * * * * for i in `seq 0 15 59`; do (sleep ${i}; bash sample.sh) & done;
「日」と「曜日」は同時に指定することができない
特定の日を指定する場合は「日」と「曜日」のどちらか一方しか指定できません。例えば「10日の水曜日の午前9時0分」と指定すると「10日の午前9時0分」か「水曜日の午前9時0分」のどちらかを満たした時にタスクが実行されてしまいます。
それでも実行したい場合は、以下のように工夫してみると良いでしょう。
水曜日の10日午前9時0分に sample.sh を実行する
0 9 * * 3 /usr/bin/test $(date +%d) -eq 10 && bash sample.sh
上記のコマンドの説明: 水曜日の午前9時0分になった場合、/usr/bin/test $(date +%d) -eq 10 && bash sample.sh
が実行されます。これは、現在の日にちが10と等しい時 sample.sh を実行する設定です。
X日おきにタスクを実行する場合、実行日がずれるケースが有る
例えば5日おきに sample.sh を実行したいとすると、以下のように記述すれば良いと思うかもしれません。
* * */5 * * bash sample.sh
しかしこの場合、31日間ある月だと実行される日は、1日、6日、11日、16日、21日、26日、31日、翌月の1日となってしまい、2日連続で実行されてしまいます。つまり「*/5
」は「1-31/5
」と同じです。
月末に実行するには工夫が必要
通常の cron では、月末指定に対応していませんが、以下のように少し工夫することでこれを実現できます。
月末の21時45分に sample.sh を実行
45 21 28-31 * * /usr/bin/test $(date -d '+1 day' +%d) -eq 1 && bash sample.sh
上記の内容を簡単に解説すると
- 28~31日の21時45分の場合 testコマンドを実行
- testコマンドで翌日が「翌月の最初の日」である場合、sample.shを実行
といった具合です。
コメント