web-dev-qa-db-ja.com

crontabが機能しないのはなぜですか?どうすればトラブルシューティングできますか?

これは、cronとcrontabの使用に関する 標準的な質問 です。

コミュニティはあなたの質問に対する答えが以下にあると確信しているので、あなたはここに導かれました。以下で質問に対する回答がない場合、回答は、コミュニティがあなたを助けるのに役立つ情報を収集するのに役立ちます。この情報は、元の質問に編集する必要があります。

なぜ私のcrontabが機能しないのですか、そしてどのようにトラブルシューティングできますか?」の答えは以下にあります。これは、crontabが強調表示されたcronシステムに対処します。

246
Eric Leschinski

すべてのcrontab関連の問題/問題を修正する方法(Linux)


これは community wiki です。この回答に誤りがあることに気付いた場合、または追加情報がある場合は、編集してください。


まず、基本的な用語:

  • cron(8) は、スケジュールされたコマンドを実行するデーモンです。
  • crontab(1) は、ユーザーのcrontab(5)ファイルを変更するために使用されるプログラムです。
  • crontab(5) は、cron(8)の指示を含むユーザーごとのファイルです。

次に、cronに関する教育:

システム上のすべてのユーザーは、独自のcrontabファイルを持っている場合があります。ルートとユーザーのcrontabファイルの場所はシステムによって異なりますが、通常は/var/spool/cronの下にあります。

システム全体の/etc/crontabファイルがあり、/etc/cron.dディレクトリにはcrontabフラグメントが含まれている場合があります。一部のLinuxディストリビューション(Red Hatなど)にも/etc/cron.{hourly,daily,weekly,monthly}があり、これはディレクトリであり、スクリプトは1時間/日/週/月ごとにroot権限で実行されます。

rootは常にcrontabコマンドを使用できます。通常のユーザーはアクセスを許可される場合とされない場合があります。コマンドcrontab -eを使用してcrontabファイルを編集し、保存すると、crondは基本的な有効性をチェックしますが、crontabファイルが正しく形成されることを保証しません。 cron.denyというファイルがあり、cronを使用できないユーザーを指定します。 cron.denyファイルの場所はシステムに依存しており、すべてのユーザーがcronを使用できるように削除できます。

コンピューターの電源が入っていないか、crondデーモンが実行されておらず、コマンドを実行する日付/時刻が過ぎている場合、crondはキャッチアップせず、過去のクエリを実行しません。

crontabの詳細、コマンドの作成方法:

Crontabコマンドは1行で表されます。 \を使用して、コマンドを複数行に拡張することはできません。ハッシュ(#)記号はコメントを表し、その行のすべてがcronによって無視されることを意味します。先頭の空白と空白行は無視されます。

コマンドでパーセント(%)記号を使用する場合は、十分に注意してください。エスケープされない限り\%は改行に変換され、エスケープされていない最初の%以降のすべてがstdinのコマンドに渡されます。

Crontabファイルには2つの形式があります。

  • ユーザーcrontab

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  *   command to be executed
    
  • システム全体の/etc/crontabおよび/etc/cron.dフラグメント

    # Example of job definition:
    # .---------------- minute (0 - 59)
    # |  .------------- hour (0 - 23)
    # |  |  .---------- day of month (1 - 31)
    # |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
    # |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7)
    # |  |  |  |  |
    # *  *  *  *  * user-name  command to be executed
    

後者にはユーザー名が必要です。コマンドは指定されたユーザーとして実行されます。

行の最初の5つのフィールドは、コマンドを実行する時間を表します。時間指定では、数字または該当する場合は日/月の名前を使用できます。

  • フィールドはスペースまたはタブで区切られます。
  • コンマ(,)は、リストを指定するために使用されます(例:1,4,6,8)。これは、1,4,6,8で実行することを意味します。
  • 範囲はダッシュ(-)で指定され、リストと組み合わせることができます。 1-3,9-12は、1と3の間、次に9と12の間を意味します。
  • /文字は、ステップを導入するために使用できます。 2/5は、2から始まり、5ごとに開始することを意味します(2、7、12、17、22 ...)。彼らは終わりを越えて折り返さない。
  • フィールド内のアスタリスク(*)は、そのフィールドの範囲全体を示します(たとえば、分フィールドの場合は0-59)。
  • 範囲とステップは組み合わせることができます。 */2は、関連するフィールドの最小値から開始し、その後2ごとに開始することを意味します。 0は分(0,2 ... 58)、1は月(1,3 ... 11)など.

Cronコマンドのデバッグ

メールをチェック!

デフォルトでは、cronはコマンドからの出力を、コマンドを実行しているユーザーにメールで送信します。出力がない場合、メールは送信されません。 cronから別のアカウントにメールを送信する場合は、crontabファイルでMAILTO環境変数を設定できます。

[email protected]
1 2 * * * /path/to/your/command

自分で出力をキャプチャする

Stdoutとstderrをファイルにリダイレクトできます。出力をキャプチャするための正確な構文は、シェルcronが使用しているものによって異なる場合があります。次に、すべての出力を/tmp/mycommand.logのファイルに保存する2つの例を示します。

1 2 * * * /path/to/your/command &>/tmp/mycommand.log
1 2 * * * /path/to/your/command >/tmp/mycommand.log 2>&1

ログを見る

Cronはsyslogを介してアクションをログに記録します。これは(設定によって異なりますが)/var/log/cronまたは/var/log/syslogに頻繁に送られます。

必要に応じて、cronステートメントを次のようにフィルタリングできます。

grep CRON /var/log/syslog 

ファイルの場所とそれらの使用方法について、cronの基本について説明しました。次に、いくつかの一般的な問題を見てみましょう。

Cronが実行されていることを確認する

Cronが実行されていない場合、コマンドはスケジュールされません...

ps -ef | grep cron | grep -v grep

あなたのようなものを得るはずです

root    1224   1  0 Nov16 ?    00:00:03 cron

または

root    2018   1  0 Nov14 ?    00:00:06 crond

再起動しない場合

/sbin/service cron start

または

/sbin/service crond start

他の方法があるかもしれません。ディストリビューションが提供するものを使用してください。

cronは、制限された環境でコマンドを実行します。

使用できる環境変数は非常に限られている可能性があります。通常、$LOGNAME$HOME$PATHなど、定義されているいくつかの変数のみを取得します。

特に注目すべきは、PATH/bin:/usr/binに制限されていることです。 「私のcronスクリプトが機能しない」問題の大部分は、この限定的なパスが原因です。コマンドが別の場所にある場合、いくつかの方法でこれを解決できます。

  1. コマンドの絶対パスを入力します。

    1 2 * * * /path/to/your/command
    
  2. Crontabファイルに適切なPATHを提供します

    PATH=/bin:/usr/bin:/path/to/something/else
    1 2 * * * command 
    

コマンドで他の環境変数が必要な場合は、crontabファイルでも定義できます。

cronはcwd == $ HOMEでコマンドを実行します

実行するプログラムがファイルシステムのどこにあるかに関係なく、cronを実行したときのプログラムの現在の作業ディレクトリはユーザーのホームディレクトリになります。プログラム内のファイルにアクセスする場合、相対パスを使用する場合はこれを考慮する必要があります。または、(できれば)どこでも完全修飾パスを使用するだけで、誰もが混乱するのを防ぐことができます。

Crontabの最後のコマンドが実行されない

Cronでは通常、コマンドを改行で終了する必要があります。 crontabを編集します。最後のコマンドを含む行の終わりに移動し、新しい行を挿入します(Enterキーを押します)。

Crontab形式を確認する

/ etc/crontabまたは/etc/cron.dのフラグメントにユーザーcrontabでフォーマットされたcrontabを使用することはできません。逆も同様です。ユーザーでフォーマットされたcrontabは行の6番目の位置にユーザー名を含みませんが、システムでフォーマットされたcrontabはユーザー名を含み、そのユーザーとしてコマンドを実行します。

/etc/cron.{hourly,daily,weekly,monthly}にファイルを置いたが実行されない

  • ファイル名に拡張子がないことを確認してください run-parts を参照してください
  • ファイルに実行権限があることを確認してください。
  • スクリプトを実行するときに何を使用するかをシステムに伝えます(例:#!/bin/shを先頭に置く)

Cronの日付に関連するバグ

日付がユーザーまたはシステムの更新、タイムゾーンなどによって最近変更された場合、crontabは不規則に動作し始め、奇妙なバグを示します。これは、下から時刻が変わったときに「やりたいことをしよう」とするcrontabの試みです。 「分」フィールドは、時間を変更すると無効になります。このシナリオでは、アスタリスクのみが受け入れられます。 cronを再起動し、インターネットに接続せずに再試行します(日付がタイムサーバーの1つにリセットする機会がありません)。

パーセント記号、再び

パーセント記号に関するアドバイスを強調するために、cronがパーセント記号を使って行う例を次に示します。

# cron entry
* * * * * cat >$HOME/cron.out%foo%bar%baz

3行を含む〜/ cron.outファイルを作成します

foo
bar
baz

これは、dateコマンドを使用する場合に特に邪魔になります。パーセント記号は必ずエスケープしてください

* * * * * /path/to/command --day "$(date "+\%Y\%m\%d")"
352
Eric Leschinski

Debian Linuxとその派生物(Ubuntu、Mintなど)には、cronジョブの実行を妨げる特性があります。特に、/etc/cron.d/etc/cron.{hourly,daily,weekly,monthly}のファイルは次のようにする必要があります。

  • ルートが所有する
  • rootのみが書き込み可能であること
  • グループまたは他のユーザーによる書き込み不可
  • 名前があるドット '。'なしまたは '-'と '_'以外のその他の特殊文字.

最後のものは、疑いを持たないユーザーを定期的に傷つけます。特に、whatever.shmycron.pytestfile.plなどの名前が付けられたこれらのフォルダーの1つにあるスクリプトは、常にnotが実行されます。

私の経験では、この特定のポイントは、Debianおよび派生物で実行されないcronjobの最も頻繁な理由でした。

必要に応じて、詳細についてはman cronをご覧ください。

25
wazoox

Cronジョブが機能しなくなった場合は、パスワードが期限切れになっていないことを確認してください。期限が切れると、すべてのcronジョブが停止します。
メッセージは/var/log/messages以下のように、ユーザーの認証に関する問題を示します。

(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)

20
Munkeh72

珍しく不規則なスケジュール

Cronはすべて非常に基本的なスケジューラと見なされており、この構文では、管理者が少し一般的でないスケジュールを簡単に作成することはできません。

一般的に "run command every 5 minutes"と説明される次のジョブを考えてみましょう。

*/5 * * * * /path/to/your/command

対:

*/7 * * * * /path/to/your/command

これはしない常にcommandを7分ごとに実行するです。

覚えている / 文字を使用してステップを導入できますが、そのステップはシリーズの終わりを超えて折り返されません。 */7は、7分ごとの0-59、つまり0,7,14,21,28,35,42,49,56から7分ごとに一致しますが、-1時間と次の時間のみバッチ間の4分00:56の後、01:0001:07などから新しいシリーズが始まります(01:0301:1001:17などではバッチは実行されません)。


代わりに何をしますか?

複数のバッチを作成

単一のcronジョブではなく、複数のバッチを作成し、それらを組み合わせて目的のスケジュールを作成します。

たとえば、40分ごとにバッチを実行するには(00:00、00:40、01:20、02:00など)、2つのバッチを作成します。1つは偶数時間に2回実行され、2つ目は奇数時間のみ実行されます。

# The following lines create a batch that runs every 40 minutes i.e.

# runs on   0:00, 0:40,        02:00, 02:40         04:00 etc to 22:40
0,40 */2 * * * /path/to/your/command

# runs on               01:20,               03:20,       etc to 23:20
20 1/2 * * * /path/to/your/command

# Combined: 0:00, 0:40, 01:20, 02:00, 02:40, 03:20, 04:00 etc.

バッチの実行頻度を減らす

複数のバッチに分解するのが難しいスケジュールである7分ごとにバッチを実行するのではなく、10分ごとに実行するだけです。

バッチをより頻繁に開始(ただし、複数のバッチが同時に実行されるのを防ぎます)

バッチランタイムが増加/変動し、同じバッチの後続の実行が重複して同時に実行されるのを防ぐために、追加の安全マージンを指定してバッチがスケジュールされるため、多くの奇妙なスケジュールが進化します。

代わりに、別の方法で考え、前回の実行がまだ完了していない場合は正常に失敗し、それ以外の場合は実行されるcronjobを作成します。これを見てください Q&A

* * * * * /usr/bin/flock -n /tmp/fcj.lockfile /usr/local/bin/frequent_cron_job 

/ usr/local/bin/frequency_cron_jobの前回の実行が完了すると、すぐに新しい実行が開始されます。

バッチをより頻繁に開始する(ただし、条件が適切でない場合は正常に終了します)

Cron構文は制限されているため、バッチジョブ自体に、より複雑な条件とロジックを配置する(または既存のバッチジョブのラッパースクリプトに配置)を選択できます。これにより、お気に入りのスクリプト言語の高度な機能を利用してコードにコメントを付け、crontabエントリ自体の読みにくい構成を防ぐことができます。

Bashでは、seven-minute-jobは次のようになります。

#!/bin/bash
# seven-minute-job
# This batch will only run when 420 seconds (7 min) have passed
# since the file /tmp/lastrun was either created or updated

if [ ! -f /tmp/lastrun ] ; then
    touch /tmp/lastrun
fi

if [ $(( $(date +%s) - $(date -r /tmp/lastrun +%s) )) -lt 420 ] ; then
     # The minimum interval of 7 minutes between successive batches hasn't passed yet.
    exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#### actual batch job is done, now update the time stamp
date > /tmp/lastrun
#EOF

安全に(試行して)毎分実行できます。

* * * * * /path/to/your/seven-minute-job

異なるが同様の問題は、毎月第1月曜日(または第2水曜日)などにバッチを実行するようにスケジュールすることになります。バッチが毎週月曜日に実行されるようにスケジュールし、日付が1とst または7番目 曜日は月曜日ではありません。

#!/bin/bash
# first-monday-of-the-month-Housekeeping-job

# exit if today is not a Monday (and prevent locale issues by using the day number) 
if [ $(date +%u) != 1 ] ; then
  exit 0
fi

# exit if today is not the first Monday
if [ $(date +%d) -gt 7 ] ; then
  exit 0
fi

####  Start running your actual batch job below

/path/to/your/command

#EOF

その後、毎週月曜日に安全に(試行して)実行できます。

0 0 * * 1 /path/to/your/first-monday-of-the-month-Housekeeping-job

cronを使用しない

ニーズが複雑な場合は、複雑なスケジュール(複数のサーバーに分散)を実行するように設計され、トリガー、ジョブの依存関係、エラー処理、再試行、再試行の監視などをサポートする、より高度な製品の使用を検討してください。業界の専門用語は「エンタープライズ」です。 " ジョブスケジューリング および/または"ワークロードオートメーション "。

14
HBruijn

PHP固有

次のようなcronジョブがある場合:

php /bla/bla/something.php >> /var/logs/somelog-for-stdout.log

そして、エラーが予想される場合、それらはあなたに送られますが、そうではありません-これをチェックしてください。

PHPはデフォルトでエラーをSTDOUTに送信しません。 @see https://bugs.php.net/bug.php?id=22839

これを修正するには、cli`s php.iniまたは行(またはPHPのbashラッパー)に以下を追加します。

  • --define display_startup_errors = 1
  • --define display_errors = 'stderr'

1番目の設定では、「メモリoops」や2番目の設定を使用して、すべてをSTDERRにリダイレクトできます。すべてがログに記録されるのではなく、ルートのメールに送信されるため、十分にスリープ状態になった後にのみ。

8
gaRex

完全を期すために、 ここから と私の回答を追加し、別の潜在的に役立つリソースを追加します。

cronユーザーは、あなたとは異なる$PATHを持っています:

ユーザーがcrontabエントリでよくある問題は、ログインしたユーザーとは異なるcronenvironmentが実行されていることを忘れることです。たとえば、ユーザーは自分の$HOMEディレクトリにプログラムまたはスクリプトを作成し、次のコマンドを入力して実行します。

$ ./certbot ... 

コマンドは彼のコマンドラインから完全に実行されます。次に、ユーザーはそのコマンドをcrontabに追加しますが、これが機能しないことがわかります。

*/10 * * * * ./certbot ....

この場合の失敗の理由は、./cronユーザーの場所であり、ログインユーザーの場所とは異なるためです。つまり、environmentは異なります。 PATHはenvironmentの一部であり、通常cronユーザーでは異なります。この問題を複雑にしているのは、environmentcronがすべての* nixディストリビューションで同じではなく、 cron のバージョンが複数あることです。

この特定の問題の簡単な解決策は、cronユーザーにcrontabエントリで完全なパスを指定することです。

0 22 * * * /path/to/certbot .....

cronユーザーのenvironmentとは何ですか?

場合によっては、システム上のenvironmentの完全なcron仕様を知っておく必要がある場合があります(または、興味があるだけかもしれません)。environmentユーザーのcronとは何ですか?それは私たちのユーザーとどう違うのですか? さらに、別のenvironmentユーザーのcronを知る必要がある場合があります-rootたとえば... rootユーザーのenvironmentとはcron?これを学ぶ1つの方法は、cronに次のことを伝えるよう依頼することです。

  1. 次のように(または任意のエディターを使用して)ホームディレクトリ(~/)にシェルスクリプトを作成します。
$ nano ~/envtst.sh
  1. システム/ユーザーに合わせて調整した後、エディターに次のように入力します。
#!/bin/sh 
/bin/echo "env report follows for user "$USER >> /home/you/envtst.sh.out 
/usr/bin/env >> /home/you/envtst.sh.out 
/bin/echo "env report for user "$USER" concluded" >> /home/you/envtst.sh.out
/bin/echo " " >> /home/you/envtst.sh.out
  1. ファイルを保存し、エディターを終了して、ファイルのアクセス許可を実行可能ファイルとして設定します。
$ chmod a+rx ~/envtst.sh
  1. 作成したスクリプトを実行し、/home/you/envtst.sh.outの出力を確認します。この出力は、現在の環境を、ログインしている$USERとして表示します。
$ ./envtst.sh $$ cat /home/you/envtst.sh.out
  1. crontabを開いて編集します。
$ crontab -e -u root
  1. crontabの下部に次の行を入力します。
* * * * *  /home/you/envtst.sh >> /home/you/envtst.sh.err 2>&1

回答:出力ファイル/home/you/envtst.sh.outには、「ルートcronユーザー」のenvironmentのリストが含まれます。それがわかったら、それに応じてcrontabエントリを調整します。

crontabエントリで必要なスケジュールを指定できません。

crontabのスケジュールエントリはman crontabで定義されているので、これを読んでください。ただし、man crontabを読み、スケジュールを理解することは2つの異なることです。そして、スケジュール仕様の試行錯誤は、非常に退屈になる可能性があります。さいわい、 crontabの第一人者を助けることができるリソースがあります。 。スケジュールの仕様を入力すると、わかりやすい英語でスケジュールが説明されます。

最後に、ここで他の回答のいずれかと重複するリスクがある場合は、スケジュールするジョブが1つあるため、単一のcrontabエントリに制限されているとは思わないでください。必要なスケジュールを取得するために必要な数のcrontabエントリを自由に使用できます。

0
Seamus