page_adsence

2011年1月27日木曜日

crontabの書き方

いつもお世話になっているcron による定期実行。「cron なんて簡単だよ」っと思ってる方は結構多いのではないだろうか。いや、実際に cron はわかりやすいプログラムだし、そんなに難しいものではない。だが、意外と覚えることが多く(メモっておけば覚える必要なんてこれっぽっちもないんだが)、自分の思うような動作をしてくれなかったりすることもあるので、ちょっとだけ cron について真剣に勉強してみることにした。まず、基本中の基本として、cron の設定ファイルは、/etc/crontab に記述されている。さらには、/etc/cron.daily/、/etc/cron.weekly/、/etc/cron.monthly/ 以下に格納された設定ファイルを1日1回、週に1回、月に1回と実行してくれるのはすでに周知のことだろう。

まず、/etc/crontab を見てみる。筆者のLANDISKでは、デフォルトでは以下のように記述されている。まず、/etc/cron.daily と、/etc/cron.weekly と /etc/cron.monthly 以下のスクリプトを実行するということは、crontab を見慣れた方ならば一目瞭然だが、test だの、run-parts だの、/usr/sbin/anacron だのは実際になにをやっているのだろうか? まず、test -x という部分を見てみる。これは、「ファイルが存在すれば実行する」ということを意味している。test -x /usr/bin/anacron で、/usr/sbin/anacronが存在するかどうかをチェックし、存在しなければを表すのが「|| 」の記号になる。run-parts はコマンドを表し、ディレクトリ内にあるスクリプトを実行するコマンドのことである。つまり、/etc/cron.daily/ 以下にあるスクリプトが実行できるようになる。結論としてこの1行は「/usr/sbin/anacronがあるかどうかチェックし、なければ、run- parts コマンドを実行しろ」ということを表している。実際に、筆者の環境では、anacron はインストールされていないので run-parts コマンドが実行されることになる。--report というオプションは、verbose みたいなものだが、スクリプトの名前のみが出力されると man には書いてあった。

landisk:~# cat /etc/crontab

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user command
17 * * * * root run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || run-parts --report /etc/cron.daily
47 6 * * 7 root test -x /usr/sbin/anacron || run-parts --report /etc/cron.weekly
52 6 1 * * root test -x /usr/sbin/anacron || run-parts --report /etc/cron.monthly

次に、左から数えて5番目のフィールドまで説明する。* (アスタリスク)があったり、数字があったりする箇所だ。率直に左からいうと、「分(minutes)・時(hour)・日(day)・月(month)・週(week)」という順番になっている。* を指定した場合は、全ての有効な値が設定されたことになります。

 分(minutes) 0-59 の間で指定する
 時(hour) 0-23 の間で指定する
 日(day) 1-31 の間で指定する
 月(month) 1-12 もしくは、名前
 週(week) 0-7 もしくは、名前。0 と 7 は日曜日。


例1) 毎朝6時25分に hoge.sh を実行する

25 6 * * * /usr/local/bin/hoge.sh

例2) 3時間ごとにhoge.shを実行する。

0 */3 * * * /usr/local/bin/hoge.sh

例3) 12月24日0時0分、クリスマスイブに hoge.sh を実行。なにが起きるんだろう。

0 0 24 12 * /usr/local/bin/hoge.sh

例4) 8時から17時の間、2時間ごとに、hoge.sh を実行する

0 8-17/2 * * * /usr/local/bin/hoge.sh

例5)毎月2日、12日、22日の12時にhoge.sh を実行する

00 12 2,12,22 * * /usr/local/bin/hoge.sh


■環境変数・シェル変数の定義

/etc/crontab の先頭には、以下のような環境変数やシェル変数を記述しておきます。cron はデフォルトでは、/etc/crontab の所有者(つまり、root )にメールを送信し、その実行結果を報告します。特定の宛先にメールを送信する場合は、MAILTO でアドレスを指定します。「MAILTO=""」のように空白を指定した場合は、誰にもメールを送信しなくなります。その他、環境変数 PATH を記述しておくことで、コマンドを絶対パスで記述する必要がなくなります。

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root




     crontab コマンド
 
/etc/crontab は直接編集するのではなく、crontab -e コマンドによって編集するのがBEST(当然?)とされています。筆者のようななんちゃってリナクサーは、直接 vi で編集してしまうのですが、作法としては良い事ではなさそうな感じです。まぁ、でも編集してはいけないということではなく、大まかな指定では、/etc /cron.{hourly,daily,weekly] で指定し、より細かく制御したい場合は、/etc/crontab もしくは、crontab -e を使ったほうが管理の面でも楽なことは確かです。あるいは、/etc/cron.d/ 以下にスクリプトを置くという手もありますね。/etc/crontab と crontab -e では、crontab が保存される場所が異なるので、編集するならどちらか片方に統一しておいた方が良いと思います(どちらか片方のファイルを見ればいいだけなので)。 crontab -e コマンドを使うと、root のみならず、一般ユーザも定期的な実行を行うことができます。その場合、/var/spool/cron/user に個別に設定が保存され、root の場合は、/var/spool/cron/root に保存されるようになる。cron の場合、設定ファイルを保存した時点で、cron が自動的に変更を検知するため、cron デーモンの再起動は必要ありません。/etc/hosts.allow などのように、保存した時点で設定が反映されます。

crontab のオプションを以下に記述します。書式に関しては、/etc/crontab と同様である。ユーザフィールド(/etc/crontab では root となっている箇所)は自分のcrontab なので省略することができる(/etc/crontab でも省略できるが)。

 -e crontabを編集する。
 -l 登録されているcrontabを表示する。
 -r 登録されているcrontab を削除する
 -u ユーザ名 設定するcrontabのユーザ名を指定する




     メール送信設定
 
cron は、 /etc/crontab に記述された処理を 指定したユーザ宛にその実行結果を送信します。これはとてもありがたい機能ですが、時として非常にうざったい機能にもなります。Logwatch のように 稼動しているサービス一覧のログを取得し、一通のメールにまとめて送信してくれるならまだしも、ひとつひとつのシェルスクリプトに対して個別にメールを送られたのではたまったものじゃありません。なので、メールを送信してもいいジョブと、送信する必要のないジョブを明確にきりわけておく必要があるでしょう。

①----
標準出力、標準エラー出力とも捨てる設定です。つまり、メールは送信しないし、ファイルにも出力しない、スクリプトを実行した記録はどこにも残らないという意味なります。

②----
標準出力を捨て、標準エラー出力をメールで送信する設定です。エラーになった処理だけを知らせてくれるので場合によっては①よりも効率が良いといえます。

③----
メール送信はしないが、/var/log/origin.log に標準出力と標準エラー出力を残すという意味になる。メールで通知を受け取るほど重要度が高くないが、一応ログには残しておきたい場合には、この方法は有効でしょう。

25 6 * * * root test -x /usr/sbin/anacron || run-parts --report /etc/cron.daily
47 6 * * 7 root test -x /usr/sbin/anacron || run-parts --report /etc/cron.weekly
52 6 1 * * root test -x /usr/sbin/anacron || run-parts --report /etc/cron.monthly

05 5 * * * root /usr/local/bin/hoge.sh > /dev/null 2>&1 ----------------①
05 5 * * * root /usr/local/bin/hoge.sh 1> /dev/null 2> /dev/null ---------①
05 5 * * * root /usr/local/bin/hoge.sh 1> /dev/null ----------------------②
05 5 * * * root (/usr/local/bin/tames.sh > /var/log/origin.lo 2>&1) > /dev/null --③