crontabの書き方や確認、仕組みや落とし穴を理解する

crontabの書き方や確認、仕組みや落とし穴を理解する

Table of Contents

定期実行といえばcron、それらスケジュールを制御するコマンドがcrontabです。

でも、たまにしか触らないのでスケジュールの書き方をよく忘れます。
それどころかコマンドの使い方すら忘れるほど触れない時期が長いコマンドですね。
そして「cronは定期実行」というコマンドとしては比較的理解しやすい役割をもつため、きちんと仕組みについて理解せずとも使えたりします。

この記事では書き方や今登録されているスケジュールの確認方法だけでなく、そもそもの動作仕組みや慣れてないとよくハマる落とし穴について、普段のメモ的な確認から基礎理解までまとめました。

cronとcrontabの違い

cron、crontab、crontabファイルと似た言葉があるので、まずは超ざっくり用語整理します。

cronとは?

crontabにスケジュールされたコマンドを実行するデーモンです。

crontabとは?

個々のユーザのcrontabファイルをメンテナンスするコマンドです。

crontabファイルとは?

crontabコマンドによって作成されたファイルです。
中身はcronが解釈可能な記法で記載されたスケジュールが並んでいます。

crontabファイルを覗いてみる

実際ファイルを覗いてみるとこんな感じです。#はコメント行です。
コメントに書いてるようにこのファイルを直接編集してはいけません。
この場合では1つスケジュールが登録されています。

# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.S21fXH5GxY installed on Sat Jun  2 23:14:39 2018)
# (Cron version -- $FreeBSD: src/usr.sbin/cron/crontab/crontab.c,v 1.24 2006/09/03 17:52:19 ru Exp $)
*/10 5-22 * * 1-5 ~/cron/sh/hoge.sh

cronの動きを理解する

crontabにスケジュールされたコマンドを実行するデーモンです。

誰がcronを起動するのか?

デーモン起動は自動です。

/etc/crontabまたは/usr/lib/cron/tabs内にファイル存在を検知すると起動します。
ユーザは手動でcronデーモンを起動する必要ありません。

どこからcrontabファイルをロードするのか?

/etc/passwdのアカウント名にちなんで名付けられたcrontabファイルを/usr/lib/cron/tabsから検索します。
見つけたcrontabはメモリ上にロードされます。
また異なる形式の/etc/crontabも検索対象です。

指定時間にコマンド実行する仕組み

cronは毎分起動してます。

cronは毎分起動し保存されてるcrontabを調べ現在の分で実行する必要があるか確認します。
コマンドを実行すると、出力はcrontab所有者またはMAILTO環境変数で指定されたユーザーにメールで送信されます。

crontabファイルを反映する方法

crontabの変更は自動更新です。

cronはcrontabが変更されたかどうかを毎分チェックしており、変更されていればcrontabファイルを再ロードします。
そのためにcrontabで変更してもcron再起動は不要です。

crontabを理解する

crontabコマンドはcrontabファイルを編集したり現在のスケジュールを確認するためのコマンドです。
crontabでスケジュール追加や変更することでcronが自動で起動またはリロードします。

crontabのtabとは?

明確な情報はありませんが、tableのtabだと思います。
crontabは行毎が1情報となっており、何個もcronがスケジュールされていると表(table)のようになるからだと思います。

crontabファイルの場所

crontabファイルは、/etc/crontabまたは/usr/lib/cron/tabs内にあります。
ファイル名はユーザー名になっています。

私のMac環境では/usr/lib/cron/tabs内にありました。

# ls /usr/lib/cron/tabs
mothule

crontabの形式

crontabファイルはフォーマットに従わなければいけません。
1行毎にスケジュールが並んでおり、1行で実行時間と実行内容が並びます。

分 時 日 月 曜日 コマンド

この順番で並んでいるなければいけません。

crontabコマンドの使い方

使用方法は次のようになります。

crontab [-u user] file
crontab [-u user] { -l | -r | -e }

オプションそれぞれについて説明します。

-u: ユーザ名の指定

crontabを調整するユーザを指定します。
未指定の場合は、実行中ユーザ のcrontabを調整します。

注意

suコマンド中にcrontabを実行するとどのユーザで実行するか不安定になるため、安全のために-uオプションが必要です。

-l: 現在のスケジュールを確認

-lオプションをつけることで、現在ロードされてるcrontabファイルを確認できます。

$ crontab -l
*/10 5-22 * * 1-5 ~/cron/sh/hoge.sh

-r: 現在のスケジュールを全て削除

-rオプションをつけることで、crontabファイルを削除します。

次のシェルは実際にcrontabファイルを削除したあとに確認してます。

$ crontab -l
*/10 5-22 * * 1-5 ~/cron/sh/hoge.sh
$ crontab -r
$ crontab -l
crontab: no crontab for mothule

-e: 現在のスケジュールを編集

-eオプションをつけることで、スケジュールを編集します。
VISUAL環境変数またはEDITOR環境変数で指定されたエディタアプリで編集します。
エディタ終了すると自動的に適用されます。

次のシェルは空の状態から新しくスケジュールを登録してます。

$ crontab -e
crontab: no crontab for mothule - using an empty one
crontab: installing new crontab

注意

ファイルを直接編集する必要があるため、ファイルのリンクを解除して再生成するエディタは使えません。

crontabの実行権限を制御する

crontabは定期実行のスケジュールを編集できるコマンドです。
実行されるコマンドによっては重要な処理だったりします。
誰でも編集できる状態だと、悪意なくとも人為的なミスが起きるリスクが存在し続けます。

このリスクヘッジとして、cron.allowとcron.denyを使うことでcrontabの実行権限を制御できます。

cron.allowcron.denyファイルはそれぞれ、/usr/lib/cron/cron.allow/usr/lib/cron/cron.denyとして配置することで有効化されます。

それぞれの中身は行ごとに1ユーザーの名前が並びます。
cron.allowファイルが存在する場合は、その中に記載されたユーザーのみが使えます。つまりホワイトリストですね。
cron.denyファイルが存在する場合は、その中に記載されたユーザーは使えません。つまりブラックリストですね。

crontabの書き方

crontabの書き方は覚えにくいです。

特性上何度も書くこともないし、他コマンドなどで同じフォーマットがないためです。

分 時 日 月 曜日 コマンド

日時の範囲

時間 値範囲
0~59
0~23
1~31
1~12 or jan~dec
曜日 0~7 or sun ~ sat

アスタリスク(*)はどの値にも当てはまる

例えば次のスケジュールは毎分実行されます。

* * * * * command

項目となる部分をアスタリスク(*)とすることで、その項目はどの値であってもパスするようになります。

, で区切ると複数時間を指定できる

月曜と水曜のみ実行

* * * * 1,3 command

-で挟むと範囲時間を指定できる

9時〜22時のみ実行

* 9-22 * * * command

*/ で割ると一定時間おきに実行する

3時間置きに実行

* */3 * * * command

※ この記法は Linux だと動かないかも

ケース別crontabの書き例

  • 1分毎に実行
  • 15分毎に実行
  • 1時間毎に実行
  • 毎日21時に実行
  • 毎週日曜の9時と21時に実行
  • 12月の平日の9時から22時までの間10分毎に実行

1分毎に実行

これは特に説明不要ですね。

* * * * * command

15分毎に実行

分を15で割ることで15分毎になります

*/15 * * * * command

1時間毎に実行

分を固定値にすることで1時間毎になります。

毎時0分に実行

0 * * * * command

毎時27分に実行

27 * * * * command

毎日21時に実行

時を固定値にすることで毎日21時に実行します

0 21 * * * command

分をアスタリスク(*)だと21時00分〜21時59分の60回実行されてしまうので注意です。

毎週日曜の9時と21時に実行

曜日で日にちを縛って、カンマで9時と21時を指定します。

0 9,21 * * sun command

曜日は数字でも英字でも指定できます。日曜日は数字だと0です

9月の平日の9時から22時までの間10分毎に実行

ハイフン(-)で月を範囲指定し、曜日で平日に制限します。

*/10 9-22 * 9 1-5 command

cronローカル活用術

cronはサーバーでバッチ処理のイメージが強いですが、個人のPCでも十分使いこなすことができます。
crontabに記載するコマンドはシェルコマンドであれば何でもいいので、外部シェルやRubyスクリプトを実行することもできます。

例えば次のスケジュールをMac上のcrontabで登録すると毎分通知をすることができます。

* * * * * /Users/mothule/.rbenv/shims/terminal-notifier -message '1分経過'

terminal-notifierによるMac通知

上記例だと単純に1分毎に決められた文言が通知されるだけですが、Rubyスクリプトなどで25分/5分のポモドーロ・テクニックを使って通知させたりもできます。 また通信して変更があればslackに通知といったこともできます。

cronの実行時エラーをログで確認する

crontabに並ぶコマンドを実行してエラーが発生したらログとして残ります。

ログが更新されたかどうかはターミナルを弄ってると通知されます。

$
You have mail in /var/mail/mothule

このパスがログとなっています。

cronだとcommand not foundが出る場合

ターミナル上では動くコマンドでもcron実行だとcommand not foundと出て実行されない場合があります。
cronが実行される環境では、コマンドへのPATHが通っていないことが考えられます。
シェルとターミナルの関係性を理解してると分かりますが、ターミナルが立ち上がるときにPATH設定など事前準備後にターミナルが立ち上がります。

cronはターミナルを通していないため、PATH環境変数が異なります。

この場合の解決方法は2つあります。

  • コマンドを絶対パスで指定
  • PATH環境変数を設定してコマンド実行

コマンドを絶対パスで指定

例えば前述したterminal-notifierコマンドであれば、私の環境での絶対パスは/Users/mothule/.rbenv/shims/terminal-notifierです。 これはwhichコマンドで調べることができます。

$ which terminal-notifier
/Users/mothule/.rbenv/shims/terminal-notifier

PATH環境変数を設定してコマンド実行

シェルコマンドは環境変数を設定してから実行することが可能です。 この仕組を使って、crontabに設定するコマンドの手前に、PATHにコマンドのパスを追加することで、コマンドだけの実行でもパスが通っていることで実行可能となります。

* * * * * PATH=$PATH:/Users/mothule/.rbenv/shims terminal-notifier -message "test"

crontabで色々な理解を深める

ただ決まった時間に実行するスケジューラーでもcronの仕組みやcronとcrontabとの関係を知ることで、理解が深まります。 落とし穴を知ることで、シェルやターミナルも少し理解が進みます。

以上がcrontabの記事でした。

このエントリーをはてなブックマークに追加