cron
Wikipedia より:
- cron は Unix ライクなコンピュータオペレーティングシステムにおける時間基準のジョブスケジューラです。cron を使うことでジョブ (コマンドやシェルスクリプト) をスケジュールして定期的に特定の時刻・時間に実行することが可能になります。システムのメンテナンスや管理を自動化するためによく使われます。
目次
インストール
cron の実装はたくさん存在しますが、デフォルトではそのいずれもインストールされません。代わりにベースシステムは systemd/タイマー を使用しています。実装の比較については Gentoo の cron ガイド を見て下さい。
公式リポジトリにあるパッケージ:
AUR にあるパッケージ:
- dcronAUR
- vixie-cronAUR
- scron-gitAUR
設定
有効化と自動起動
デーモンをインストールしても、デフォルトでは有効になっていません。インストールしたパッケージにはサービスが入っているので、systemctl を使用してコントロールすることができます。例えば、cronie を起動して有効化するには:
# systemctl start cronie # systemctl enable cronie
これらのコマンドはあなたが選んだ実装に合わせて変更してください、例えば:
# systemctl start dcron # systemctl enable dcron
/etc/cron.daily/
や同じようなディレクトリを見てジョブが存在するか確認してください。cron サービスを有効にすることで、それらのジョブが作動します。
ジョブのエラーの対処
cron は stdout や stderr からの出力を記録して sendmail
コマンドを使ってユーザーのスプールにメールで送信しようと試みます。/usr/bin/sendmail
が存在しない場合 Cronie はメール出力を無効化します。これらのメッセージをログとして記録するには -m
オプションを使ってスクリプトを書くか基本的な SMTP サブシステムをインストールしてください。
ssmtp の例
ssmtp は送信だけを行う sendmail エミュレータで、ローカルコンピュータから smtp サーバーにメールを送信できます。活発なメンテナンスはされていませんが、設定済みのメールハブに対してメールを転送する方法としては最もシンプルです。デーモンを実行する必要はなく、設定ファイルを3行編集するだけで設定できます (認証されていないメールをメールハブでリレー出来る場合)。ssmtp はメールを受け取ったり、エイリアスを展開したり、キューを管理したりはしません。
ssmtp をインストールしてください。/usr/bin/sendmail
から /usr/bin/ssmtp
にシンボリックリンクが作成されます。インストールしたら /etc/ssmtp/ssmtp.conf
を編集してください。詳しくは ssmtp を参照。/usr/bin/sendmail
に対してシンボリックリンクが作成されることで S-nail などのプログラム (/usr/bin/mail
を提供するパッケージ) をそのまま使うことが可能です。
/usr/bin/sendmail
がインストールされていることを認識されるために cronie
を再起動してください。
msmtp の例
msmtp を使って cronie からメールを取得する方法は2つあります:
- msmtp-mta パッケージをインストールします。
/usr/bin/sendmail
から/usr/bin/msmtp
にシンボリックリンクが作成されます。cronie
を再起動して新しいsendmail
コマンドが検出されていることを確認してください。msmtp にユーザー名をメールアドレスに変換する手段を用意する必要があります。- 次のように crontab に
MAILTO
行を追加する:MAILTO=your@email.com
または: /etc/msmtprc
に次の行を加えて:aliases /etc/aliases
/etc/aliases
を作成してください:your_username: your@email.com
# Optional:
default: your@email.com
- 次のように crontab に
cronie.service
ユニットを編集します。例えば、/etc/systemd/system/cronie.service.d/msmtp.conf
を作成してください:[Service] ExecStart= ExecStart=/usr/bin/crond -n -m '/usr/bin/msmtp -t'
esmtp の例
esmtp と procmail をインストールしてください。
インストールした後、ルーティングを設定してください:
/etc/esmtprc
identity myself@myisp.com hostname mail.myisp.com:25 username "myself" password "secret" starttls enabled default mda "/usr/bin/procmail -d%T"
Procmail は配送モードで動作するのに root 権限を必要としますが cronjob を root で実行している場合は問題になりません。
正しく動作しているかテストするには、ファイル message.txt
を作成して中に "test message"
を記述してください。
同じディレクトリから次を実行してください:
$ sendmail user_name < message.txt
そして:
$ cat /var/spool/mail/user_name
テストメッセージと送信された日時が表示されるはずです。
全てのジョブのエラー出力は /var/spool/mail/user_name
にリダイレクトされます。
権限の問題で、root にメールを作成・送信するのは困難です (例: su -c ""
)。esmtp
の設定で root のメールを全て通常のユーザーに転送させることができます:
/etc/esmtprc
force_mda="user-name"
opensmtpd の例
opensmtpd をインストールしてください。
/etc/smtpd/smtpd.conf
を編集します。以下の設定でローカル配信が可能になります:
listen on localhost accept for local deliver to mbox
次のコマンドでテストが行えます:
# systemctl start smtpd $ echo test | sendmail user
user は mbox フォーマットを扱えるメールクライアントを使うか、/var/spool/mail/user
ファイルを見ることでメールを確認できます。全てが問題なく動作するようでしたら、opensmtpd を有効にします:
# systemctl enable smtpd
この方法には、リモートサーバーに cron のローカルな通知が送信しないという利点があります。ネットワーク接続も必要ありません。欠点としては、新しいデーモンを実行する必要があります。
長い cron ジョブ
仮に cron によって以下のプログラムが実行されると:
#!/bin/sh echo "I had a recoverable error!" sleep 1h
以下のことが起こります:
- cron がスクリプトを実行
- 出力があったらすぐに、cron は MTA を実行し、MTA にヘッダーをわたす。ジョブは完了しておらず、出力がまだあるかもしれないので、パイプは開きっぱなしになる。
- MTA は postfix との接続を開いて、残りのボディが来るまで待っている間、接続を開き続ける。
- 一時間以内に postfix はアイドル状態の接続を閉じて、以下のようなエラーを表示する:
smtpmsg='421 … Error: timeout exceeded' errormsg='the server did not accept the mail'
moreutils の chronic または sponge コマンドを使うことでこの問題は解決できます。それぞれの man ページより:
- chronic
- chronic はコマンドを実行して、コマンドが失敗した場合にのみ (0以外の終了コードが吐かれたりクラッシュしたとき)、標準出力や標準エラーが表示されるようにします。コマンドが問題なく実行されたときは、何も出力されません。
- sponge
- sponge は標準入力を読み込んで指定されたファイルに書き出します。シェルのリダイレクトと違って、sponge は出力ファイルを開く前のあらゆる入力を吸い上げてしまいます。出力ファイルが指定されなかったときは、sponge は標準出力に出力します。
マニュアルには載っていませんが、chronic は標準出力を開く前のコマンド出力をバッファします (sponge も同じようにバッファを使います)。
Crontab のフォーマット
crontab の基本的なフォーマットは:
minute hour day_of_month month day_of_week command
- minute は 0 から 59 までの値。
- hour は 0 から 23 までの値。
- day_of_month は 1 から 31 までの値。
- month は 1 から 12 までの値。
- day_of_week は 0 から 6 までの値、0 が日曜日。
カンマを使うことで複数の時間を指定することが出来ます。時間の範囲はハイフンで決めることができ、アスタリスクはワイルドカード文字になります。スペースはフィールドを分けるのに使います。例えば、次の行はスクリプト i_love_cron.sh
を夏の期間 (6月, 7月, 8月) を除く平日の午前9時から午後4:55まで5分間隔で実行します:
*/5 9-16 * 1-5,9-12 1-5 ~/bin/i_love_cron.sh
さらに、crontab には特殊なキーワードもいくつか存在します:
@reboot : 起動時 @yearly : 一年毎 @annually ( == @yearly) @monthly : 一月毎 @weekly : 一周毎 @daily : 一日毎 @midnight ( == @daily) @hourly : 一時間毎
例えば、起動時に i_love_cron.sh
を実行する場合:
@reboot ~/bin/i_love_cron.sh
参照: http://www.adminschoice.com/crontab-quick-reference
基本的なコマンド
Crontab を直接編集してはいけません。代わりに、ユーザーは crontab
プログラムを使って crontab を編集してください。このコマンドを実行するには、ユーザーは users グループのメンバーである必要があります (gpasswd
コマンドを見て下さい)。
crontab を一覧するには、次のコマンドを実行してください:
$ crontab -l
crontab を編集するには、次のコマンドを使って下さい:
$ crontab -e
crontab を削除するには、次のコマンドを使って下さい:
$ crontab -r
既に crontab が存在していて、古い crontab を完全に上書きするには次を使って下さい:
$ crontab saved_crontab_filename
コマンドライン (Wikipedia:ja:標準ストリーム) から crontab を上書きするには:
$ crontab -
他の誰かの crontab を編集するには、次のコマンドを root で実行してください:
# crontab -u username -e
同じフォーマット (コマンドに -u username
を追加すること) は crontab の表示・削除にも使えます。
サンプル
コマンド /bin/echo Hello, world!
を毎月の毎日の毎時間の1分目 (つまり 12:01, 1:01, 2:01 ...) に実行するエントリ:
01 * * * * /bin/echo Hello, world!
1月の平日に5分ごと (つまり 12:00, 12:05, 12:10 ...) に同じジョブを実行するエントリ:
*/5 * * jan mon-fri /bin/echo Hello, world!
次の行は夏 (6月, 7月, 8月) 以外の毎月の平日 (月-金) の午前9時から午後5時まで5分間隔で (午後5時0分は除く) スクリプト i_love_cron.sh
を実行します ("man 5 crontab" より):
*0,*5 9-16 * 1-5,9-12 1-5 /home/user/bin/i_love_cron.sh
定期的な設定は次の crontab テンプレートのように入力することも可能です:
# Chronological table of program loadings # Edit with "crontab" for proper functionality, "man 5 crontab" for formatting # User: johndoe # mm hh DD MM W /path/progam [--option]... ( W = weekday: 0-6 [Sun=0] ) 21 01 * * * /usr/bin/systemctl hibernate @weekly $HOME/.local/bin/trash-empty
デフォルトエディタ
デフォルトエディタを変更するには、シェルの初期化スクリプトで EDITOR
環境変数を定義してください (vim ユーザーは vim-default-editorAUR[リンク切れ: アーカイブ: aur-mirror] が使えます)。例:
/etc/profile.d/nano-default-editor.sh
#!/bin/sh export EDITOR=/usr/bin/nano
環境変数が正しく使われるようにするために、通常ユーザーでは、sudo
の代わりに su
を使う必要があります:
$ su -c "crontab -e"
上記のコマンドをエイリアスにするときは printf
が必要です。su
を使うと新しいシェルが起動するためです:
alias scron="su -c $(printf "%q " "crontab -e")"
run-parts 問題
cronie は run-parts
を使用して cron.daily
/cron.weekly
/cron.monthly
のスクリプトを実行します。それらのスクリプトの名前にはドット (.) を含められないので注意してください (例: backup.sh
)。オプションを付けないと run-parts
がスクリプトを無視してしまうためです (参照: man run-parts
)。
X.org サーバーを使用するアプリケーションを実行
Cron は X.org サーバー下では実行されないため、X.org サーバーアプリケーションを実行するために必要な環境変数を知りません。そのため、環境変数を定義する必要があります。xuserrunAUR[リンク切れ: アーカイブ: aur-mirror] などのプログラムを使うことで X.org アプリケーションを実行できます:
17 02 * ... /usr/bin/xuserrun /usr/bin/xclock
もしくは環境変数を手動で定義する方法もあります (echo $DISPLAY
で現在の DISPLAY の値がわかります):
17 02 * ... env DISPLAY=:0 /usr/bin/xclock
SSH などを通す場合は、権限を与えてください:
# xhost +si:localuser:$(whoami)
非同期のジョブ処理
コンピュータをオフにしてもジョブがちゃんと実行されるようにしたい場合、複数の解決方法が存在します (簡単な順番で並んでいます):
Cronie
Cronie には anacron が含まれています。プロジェクトのホームページより:
Cronie には特定時刻に指定したプログラムを起動するための標準 UNIX デーモンである crond と関連ツールが含まれています。Cronie はオリジナルの cron をベースとしており、pam や SELinux を利用できるようにするなどの改善がされています。
Dcron
dcronAUR は標準で非同期のジョブ処理をサポートしています。以下のようにジョブの名前に @hourly, @daily, @weekly, @monthly を付けて下さい:
@hourly ID=greatest_ever_job echo This job is very useful.
Cronwhip
cronwhipAUR は見過ごされた cron ジョブを自動的に実行するスクリプトです。昔 Arch でデフォルトの cron 実装だった dcron で動作します。フォーラムスレッド も参照。
Anacron
Anacron はジョブを非同期に処理する dcron を完全に置き換えます。
Anacron は cronie に含まれており、設定ファイルは /etc/anacrontab
です。フォーマットの情報は anacrontab(5)
man ページにあります。anacron -T
を実行することで /etc/anacrontab
に問題がないかテストすることができます。
Fcron
anacron と同じように、fcron はコンピュータの電源が落ちている場合を想定しますが、anacron とは違って、一日よりも短いインターバルでイベントを組むことができます。定期的にサスペンド・ハイバネートを行うような環境 (ノートパソコンなど) で有用です。cronwhip と同様に、fcron はコンピュータが落ちている間に実行すべきだったジョブを実行します。
cronie を fcron で置き換える場合、spool ディレクトリが /var/spool/fcron
になり、ユーザーの crontab を編集するときに crontab の代わりに fcrontab
コマンドを使うことになるので注意してください。crontab はバイナリ形式で保存され、spool ディレクトリに foo.orig という名前のテキストファイルが出来ます。手動でユーザーの crontab を編集するスクリプトを使っているのであれば、修正が必要です。
伝統的なユーザーの crontab を fcron 方式に変換するクイックスクリプトレット:
cd /var/spool/cron && ( for ctab in *; do fcrontab ${ctab} -u ${ctab} done )
フォーラムスレッド も参照。
排他性の確保
ジョブの実行時間が長くなる可能性がある場合 (例えばシステムのバックアップは変更箇所が多かったりネットワーク接続が遅かったりして長くなることがあります)、flock
(util-linux) を使うことで cron ジョブが二重に実行されないようにすることができます。
5,35 * * * * /usr/bin/flock -n /tmp/lock.backup /root/make-backup.sh
cronie
vixie-cron (伝統的な cron) をずっと使っていた場合 cronie の設定方法に困惑させられるかもしれません。ファイル階層は以下のとおりになっています:
/etc |----- anacrontab |----- cron.d | ----- 0hourly |----- cron.daily |----- cron.deny |----- cron.hourly | ----- 0anacron |----- cron.monthly |----- cron.weekly |----- crontab
crontab ファイルはデフォルトでは作成されませんが、追加されたジョブは実行されます。Cronie は cron と anacron の両方の機能を提供します。マシンの時刻が指定した日時になったときに cron は特定の間隔 (精度は1分まで) でジョブを実行するのに対して、anacron は特定日時にマシンの電源が入っているかどうか関係なくジョブを実行します (精度は最低1日)。マシンの電源が入ると、anacron は実行しておくべきジョブがないかどうか確認して、あれば実行します。/etc/cron.d
と /etc/cron.hourly
ディレクトリは cron 機能で使用し、/etc/anacrontab
ファイルと /etc/cron.daily
, /etc/cron.weekly
, /etc/cron.monthly
ディレクトリは anacron 機能で使用します。/etc/cron.deny
ファイルは特にジョブの作成を禁止されていないユーザーが cron ジョブを作成することができます。
システム全体の cron ジョブを作りたい場合、crontab のようなファイルを作成して /etc/cron.d
ディレクトリに配置するか /etc/crontab
にジョブを追加してください。/etc/cron.hourly
に存在する実行可能ファイル (普通は全てシェルスクリプト) は毎時間実行されます。
Anacron 機能も同じように実装されていますが、使用するのは /etc/cron.daily
, /etc/cron.weekly
, /etc/cron.monthly
ディレクトリで、ジョブを実行する間隔で決めます。anacron のジョブファイルも実行可能ファイルです。crontab フォーマットではありません。Anacron は毎時間 crontab ファイルの /etc/cron.d/0hourly
によって /etc/cron.hourly
の中にある /etc/cron.hourly/0anacron
ファイルから実行されます。ファイルを削除すると anacron が実行されなくなります。
Dcron
cron デーモンは crontab
という名前の設定ファイルをパースします。各ユーザーは別々の crontab ファイルを使うことで別個にコマンドを実行することができます。root ユーザーの crontab はシステム全体のコマンドのスケジュールを組みために使います (cron の実装によっては、ユーザーが /etc/crontab
や /etc/cron.d
ディレクトリを使うことができる場合もあります)。
/var/spool/cron/root
# Run command at a scheduled time # Edit this 'crontab -e' for error checking, man 1 crontab for acceptable format # <@freq> <tags and command> @hourly ID=sys-hourly /usr/sbin/run-cron /etc/cron.hourly @daily ID=sys-daily /usr/sbin/run-cron /etc/cron.daily @weekly ID=sys-weekly /usr/sbin/run-cron /etc/cron.weekly @monthly ID=sys-monthly /usr/sbin/run-cron /etc/cron.monthly # mm hh DD MM W /path/command (or tags) # W = week: 0-6, Sun=0 21 01 * * * /usr/bin/systemctl suspend
以下の行は crontab エントリのフォーマットの例です。空白で区切られたフィールドに以下を指定します:
- @period
- ID=jobname (this tag is specific to dcron)
- command
crontab エントリの他の標準フォーマット:
- minute
- hour
- day
- month
- day of week
- command
crontab ファイルは通常 /var/spool/cron/username
に保存され、root の crontab ファイルは /var/spool/cron/root
になります。
詳しい情報や設定例は crontab の man ページを見てください。