Debianのcron(タスクスケジューラ)
Debianを使っているとタスクスケジューラであるcronを利用することがあると思います。使ってないという人でも実はバックグラウンドで動いていて、おそらくその恩恵を受けているでしょう。
今回はそのようなcronについて認識を深めたいと思います。
基本的な使い方
crontab -eでユーザーが管理するcornのスケジュールを編集することができます。ユーザー毎ですので、root(管理者)で設定することもできます。
基本的な書式は次のようになっています。
分 | 時 | 日 | 月 | 曜日 | コマンド |
5 | 10 | * | * | * | /home/user/update.sh |
*はすべての時間を意味します。例では毎日10時5分にupdate.shを実行する設定です。
1,30とすると1と30、1-30とすると1~30の指定ができます。
実行間隔を指定したい場合は/を使います。例えば時間の場所で9-17/2とすると9時から始まり以降17時まで2時間おきという指定になります。
曜日は0:日曜日~6:土曜日となります。
ちょっとした使い方
- バックアップと全削除
crontabコマンドには、編集の際の-eオプションのほかに、設定を全削除する-r、内容を表示する-lがあります。バックアップを取っておきたい場合はcrontab -l >crontab.bkupとすると早いです。復元時はcrontabコマンドにファイルパスを引数にします。
# バックアップ crontab -l >crontab.bkup # 全削除 crontab -r # 復元 crontab crontab.bkup
- 再起動時の実行
すべての環境で使えるとは限らないですが、
@reboot command.shという書き方により、起動時に一回実行されるスクリプトを設定できます。
- エディタの変更
Debianではcrontab -eの初回実行時に利用するエディタをnanoにするかvimにするか確認してきますが、それを再度出したい場合があるかもしれません。murapong's blog:crontabを編集するエディタを変更するにはによると、select-editorとすると出てくるそうです。情報ありがとうございました。
- 秒単位の実行
指定可能なジョブの間隔の最小単位は1分ですが、sleepコマンドを使って並列に並べることで、秒単位にもできます。たとえば20秒毎に実行するなら次のようになります。
* * * * * command * * * * * sleep 20; command * * * * * sleep 40; command
複数のcrontab
crontab -eでユーザーが管理するcornのスケジュールを編集することができますが、普段cronが実行しているスケジュールはそれだけではありません。管理者やほかのユーザーのものはもちろん、monthly、weekly、daily、hourlyと定義されているものや、プログラム毎に個別に定義されているものも実行しています。
それらの定義はどこに入っているかというと、環境ごとに違かもしれませんが筆者が使用しているDebian 10.3だと次のようになっていました。
- ユーザー毎のcron
通常crontab -eとして編集するスケジュールは/var/spool/cron/crontabsにユーザー名毎に入っています。
- 時間、日、週、月
定期に実行するcronスケジュールは/etcディレクトリに存在します。それぞれcronという接頭のあとに.hourly、.daily、.weekly、monthlyというように期間を示す名前のついたディレクトリが存在します。それらの中には管理しているアプリの名称がつけられたファイル群が入ってます。これらの中身はcrontabファイルでなく、スクリプトファイルとなっています。
これらのスクリプトファイルがいつ実行するかという設定は/etc/crontabに入っています。ここを見ることで、日次のスケジュールが何時に実行されるかといった事がわかります。
- アプリ毎のcron
/etc/cron.dには、アプリ毎のcrontabが入っています。筆者の環境では、30分毎にPHPセッション情報をクリアするためのcrontabがphpというファイル名称で入っていました。
これらのファイルに記載されたことをcronは実行してくれます。
cronから送信されるメッセージ
通常crontabに何かスクリプトを登録するとその実行結果が逐次メールメッセージとして送信されます。気づくと多くのメールがたまっています。これを解消するにはcrontabのエントリーの最後を次のようにします。
後日の追記
近年のDebianでは(筆者が確認したのはbullseyeからです)、デフォルトでMUAやMTAがインストールされなくなったようです。そのためcronのメールメッセージも送信されなくなりました。これはコマンドライン上でもよくするように結果をリダイレクトしているだけです。最初の>は1>の省略形です。1は何を意味するかというと「ファイルディスクリプタ」といって、Linuxが入出力を管理するための通し番号です。1は常に「標準出力」となり2は「標準エラー出力」となります。ちなみに、ファイルディスクリプタは以降の数値でファイルにも割り当てられたりします。
このリダイレクトでは1(=標準出力)を/dev/nullに出力しています。/dev/nullは底抜けのゴミ箱のようなもので、そこにリダイレクトすることでメッセージは消えます。2>&1は「標準エラー出力」を「標準出力」に転送する設定です。出力先にファイルディスクリプタを指定する場合は先頭に&を付けるルールとなっています。
リダイレクトの機能を使っていますので、出力を(メールではなく)ファイルに保存したい場合は/dev/nullの箇所を保存先のファイルパスに変更するだけです。
この時、エラー時だけメッセージを受け取りたい場合は2>&1の部分を。変更します。
>>(アペンド出力)にして、ファイルパスを指定することも可能です。
ここまではリダイレクトとしてファイルに保存する方法を紹介しましたが、|(パイプ)を用いれば別のプログラムに標準出力を渡すことができます。
パイプは標準出力しか渡しませんので、エラーも渡したい場合は2>&1としてエラー出力を標準出力に渡します。
エラー出力だけパイプしたい場合は、エラーを標準出力に流したうえで、標準出力は/dev/nullへ流します。
.shファイル内で標準出力を受け取るには、「Bash シェルスクリプトで標準入力を受け取る」にあるように、「cat -」を使います。
一方で、メッセージをPCのメールボックスではなく別のメールアドレスに送信してほしい事もあるかもしれません。その場合はcrontabの中に次の環境変数の設定を記述することで、指定したメールアドレスにメールを送信します。
cronのログ
cronのログを統合して管理したい場合は、rsyslogの設定を変更する必要があります。環境によってはなにもしないでも出力されているかもしれません。rsyslogではcron用にcronというファシリティが用意されていますので、そのファシリティに対しての出力先を/etc/rsyslog.confに記述します。
設定変更後はrsyslogの再起動が必要です。
参考にさせていただきましたサイトの皆様、ありがとうございました。