cron (日本語) - ArchWiki

# cron (日本語)

関連記事

- systemd/タイマー

Wikipedia より:

cron は Unix ライクなコンピュータオペレーティングシステムにおける時間基準のジョブスケジューラです。cron を使うことでジョブ (コマンドやシェルスクリプト) をスケジュールして定期的に特定の時刻・時間に実行することが可能になります。システムのメンテナンスや管理を自動化するためによく使われます。

## インストール

cron の実装はたくさん存在しますが、デフォルトではそのいずれもインストールされません。代わりにベースシステムは systemd/タイマー を使用しています。実装の比較については Gentoo の cron ガイド を見て下さい。

公式リポジトリにあるパッケージ:

- cronie
- fcron

AUR にあるパッケージ:

- bcron
- dcron
- vixie-cron

## 設定

### 有効化と自動起動

デーモンをインストールしても、デフォルトでは有効になっていません。インストールしたパッケージにはサービスが入っているので、systemctl を使用してコントロールすることができます。例えば、cronie を起動して有効化するには:

    # systemctl start cronie
    # systemctl enable cronie

これらのコマンドはあなたが選んだ実装に合わせて変更してください、例えば:

    # systemctl start dcron
    # systemctl enable dcron

`/etc/cron.daily/` や同じようなディレクトリを見てジョブが存在するか確認してください。cron サービスを有効にすることで、それらのジョブが作動します。

Note: cronie には他のジョブの実行を遅延させるための、`0anacron` hourly ジョブが存在します。例えばコンピュータの電源を切った場合の標準実行の時があたります。

### ジョブのエラーの対処

cron は stdout や stderr からの出力を記録して `sendmail` コマンドを使ってユーザーのスプールにメールで送信しようと試みます。`/usr/bin/sendmail` が存在しない場合 Cronie はメール出力を無効化します。これらのメッセージをログとして記録するには `-m` オプションを使ってスクリプトを書くか基本的な SMTP サブシステムをインストールしてください。

1. `cronie.service` ユニットを編集する。
2. esmtp, msmtp, opensmtpd をインストールする、もしくはカスタムスクリプトを書く。

#### msmtp の例

msmtp を使って cronie からメールを取得する方法は2つあります:

1. 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

2. `cronie.service` ユニットを編集します。例えば、`/etc/systemd/system/cronie.service.d/msmtp.conf` を作成してください:

       [Service]
       ExecStart=
       ExecStart=/usr/bin/crond -n -m '/usr/bin/msmtp -t'

Note: The empty `ExecStart=` cancels any previous `ExecStart` commands.

#### 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"

Note: 上記のテストが上手く行かない場合、同じ内容で `~/.esmtprc` にローカルの設定を作成してみて下さい。

適切なパーミッションにするために次のコマンドを実行してください:

    $ chmod 710 ~/.esmtprc

それから `message.txt` でまたテストしてください。

#### 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 のローカルな通知が送信しないという利点があります。ネットワーク接続も必要ありません。欠点としては、新しいデーモンを実行する必要があります。

Note:

- 執筆時点では Arch の opensmtpd パッケージは `/var/spool/mail/user` 下に必要なディレクトリを全て作成しません。ただし、デーモンが必要な所有者とパーミッションについて警告を出すので、それに従ってディレクトリを作成してください。
- 上記の設定はリモート接続を受け入れませんが、用心として iptables などを使ってセキュリティレイヤーでポート25をブロックするのも良いでしょう。

#### 長い cron ジョブ

仮に cron によって以下のプログラムが実行されると:

    #!/bin/sh
    echo "I had a recoverable error!"
    sleep 1h

以下のことが起こります:

1. cron がスクリプトを実行
2. 出力があったらすぐに、cron は MTA を実行し、MTA にヘッダーをわたす。ジョブは完了しておらず、出力がまだあるかもしれないので、パイプは開きっぱなしになる。
3. MTA は postfix との接続を開いて、残りのボディが来るまで待っている間、接続を開き続ける。
4. 一時間より早く postfix はアイドル状態の接続を閉じて、以下のようなエラーを表示する:

    smtpmsg='421 … Error: timeout exceeded' errormsg='the server did not accept the mail'

moreutils の chronic または sponge コマンドを使うことでこの問題は解決できます。それぞれの man ページより:

chronic
  chronic runs a command, and arranges for its standard out and standard error to only be displayed if the command fails (exits nonzero or crashes). If the command succeeds, any extraneous output will be hidden.
sponge
  sponge reads standard input and writes it out to the specified file. Unlike a shell redirect, sponge soaks up all its input before opening the output file… If no output file is specified, sponge outputs to stdout.

Even if it's not said chronic buffer the command output before opening its standard output (like sponge does).

## 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分間隔で実行します:

    *0,*5 9-16 * 1-5,9-12 1-5 ~/bin/i_love_cron.sh

他の例や高度な設定テクニックは下を見て下さい。

## 基本的なコマンド

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-editor[broken link: package not found] が使えます)。例:

    /etc/profile.d/nano-default-editor.sh

    #!/bin/sh

    export EDITOR=/usr/bin/nano

環境変数が正しく使われるようにするために、通常ユーザーでは、`sudo` の代わりに `su` を使う必要があります:

    $ su -c "crontab -e"

To have an alias to this `printf` is required to carry the arbitrary string because `su` launches in a new shell:

    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 does not run under the X.org server therefore it cannot know the environmental variable necessary to be able to start an X.org server application so they will have to be defined. One can use a program like xuserrun to do it:

    17 02 * ... /usr/bin/xuserrun /usr/bin/xclock

Or then can be defined manually (`echo $DISPLAY` will give the current DISPLAY value):

    17 02 * ... env DISPLAY=:0 /usr/bin/xclock

If done through say SSH, permission will need be given:

    # xhost +si:localuser:$(whoami)

## 非同期のジョブ処理

If you regularly turn off your computer but do not want to miss jobs, there are some solutions available (easiest to hardest):

### Cronie

Cronie には anacron が含まれています。

### Dcron

dcron は標準で非同期のジョブ処理をサポートしています。以下のようにジョブの名前に @hourly, @daily, @weekly, @monthly を付けて下さい:

    @hourly         ID=greatest_ever_job      echo This job is very useful.

### Cronwhip

cronwhip is a script to automatically run missed cron jobs; it works with the former default cron implementation, dcron. See also the forum thread.

### Anacron

anacron[broken link: package not found] はジョブを非同期に処理する dcron を完全に置き換えます。

### Fcron

Like anacron, fcron assumes the computer is not always running and, unlike anacron, it can schedule events at intervals shorter than a single day which may be useful for systems which suspend/hibernate regularly (such as a laptop). Like cronwhip, fcron can run jobs that should have been run during the computer's downtime.

When replacing cronie with fcron be aware the spool directory is `/var/spool/fcron` and the `fcrontab` command is used instead of crontab to edit the user crontabs. These crontabs are stored in a binary format with the text version next to them as foo.orig in the spool directory. Any scripts which manually edit user crontabs may need to be adjusted due to this difference in behavior.

A quick scriptlet which may aide in converting traditional user crontabs to fcron format:

    cd /var/spool/cron && (
     for ctab in *; do
      fcrontab ${ctab} -u ${ctab}
     done
    )

See also the forum thread.

## 排他性の確保

If you run potentially long-running jobs (e.g., a backup might all of a sudden run for a long time, because of many changes or a particular slow network connection), then lockrun can ensure that the cron job won't start a second time.

      5,35 * * * * /usr/bin/lockrun -n /tmp/lock.backup /root/make-backup.sh

## Dcron

The cron daemon parses a configuration file known as `crontab`. Each user on the system can maintain a separate crontab file to schedule commands individually. The root user's crontab is used to schedule system-wide tasks (though users may opt to use `/etc/crontab` or the `/etc/cron.d` directory, depending on which cron implementation they choose).

    /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

These lines exemplify one of the formats that crontab entries can have, namely whitespace-separated fields specifying:

1. @period
2. ID=jobname (this tag is specific to dcron)
3. command

The other standard format for crontab entries is:

1. minute
2. hour
3. day
4. month
5. day of week
6. command

The crontab files themselves are usually stored as `/var/spool/cron/username`. For example, root's crontab is found at `/var/spool/cron/root`

See the crontab man page for further information and configuration examples.

## 参照

- Gentoo Linux Cron Guide

Category:

- Daemons and system services (日本語)