解決策 1:
crontab 関連の問題/問題をすべて修正する方法 (Linux)
<ブロック引用>これはコミュニティ ウィキです。この回答に間違いがある場合や追加情報がある場合は、編集してください。
まず、基本的な用語:
- cron(8) スケジュールされたコマンドを実行するデーモンです。
- crontab(1) ユーザーの crontab(5) ファイルを変更するために使用されるプログラムです。
- crontab(5) cron(8) の指示を含むユーザーごとのファイルです。
次に、cron に関する教育:
システム上のすべてのユーザーは、独自の crontab ファイルを持っている場合があります。ルートおよびユーザーの crontab ファイルの場所はシステムによって異なりますが、通常は /var/spool/cron
より下にあります。 .
システム全体の /etc/crontab
があります ファイル、/etc/cron.d
ディレクトリには、cron によって読み取られ、実行される crontab フラグメントが含まれている場合があります。一部の Linux ディストリビューション (Red Hat など) にも /etc/cron.{hourly,daily,weekly,monthly}
があります。 これらはディレクトリであり、ルート権限で毎時間/日/週/月に実行される内部のスクリプトです。
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 2 * * * /path/to/your/command
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 を参照してください
- ファイルに実行権限があることを確認してください。
- スクリプトの実行時に何を使用するかをシステムに指示します (例:put
#!/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")"
須藤に注意
root 以外のユーザーとして実行している場合、
crontab -e
ユーザーの crontab を開きますが、
sudo crontab -e
root ユーザーの crontab を開きます。 cron ジョブで sudo コマンドを実行することはお勧めできません。そのため、ユーザーの cron で sudo コマンドを実行しようとしている場合は、そのコマンドをルートの cron に移動して、コマンドから sudo を削除してみてください。
解決策 2:
Debian Linux とその派生物 (Ubuntu、Mint など) には、cron ジョブの実行を妨げる可能性があるいくつかの特性があります。特に、/etc/cron.d
のファイル 、 /etc/cron.{hourly,daily,weekly,monthly}
する必要があります:
- root が所有する
- root のみが書き込み可能
- グループまたは他のユーザーが書き込み不可
- ドット「.」を含まない名前を持っている または「-」と「_」以外のその他の特殊文字。
最後のものは、疑いを持たないユーザーを定期的に傷つけます。特に、whatever.sh
という名前のこれらのフォルダーのいずれかにあるスクリプト 、 mycron.py
、 testfile.pl
などはしません 実行されます。
私の経験では、この特定の点が、Debian および派生物で実行されない cronjob の最も頻繁な理由でした。
man cron
を参照 必要に応じて詳細を確認してください。
解決策 3:
cron ジョブが機能しなくなった場合は、パスワードの有効期限が切れていないことを確認してください。有効期限が切れると、すべての cron ジョブが停止するためです。
/var/log/messages
にメッセージがあります ユーザーの認証に関する問題を示す以下のようなもの:
(username) FAILED to authorize user with PAM (Authentication token is no longer valid; new one required)
解決策 4:
珍しく不規則なスケジュール
Cron はすべてが非常に基本的なスケジューラと見なされており、その構文では、管理者が少し珍しいスケジュールを作成することは容易ではありません.
次のジョブについて考えてみましょう。これは一般的に 「command
を実行する」と説明されます 5分ごと」 :
*/5 * * * * /path/to/your/command
対:
*/7 * * * * /path/to/your/command
常にそうではない command
を実行 7分ごと .
/ 文字を使用してステップを導入できますが、そのステップはシリーズの終わりを超えて折り返されません。 */7
分 0-59
から 7 分ごとに一致します 例:0、7、14、21、28、35、42、49、56 ただし、1 時間と次の時間の間 バッチ間の間隔はわずか 4 分です 、 00:56
の後 新しいシリーズは 01:00
から始まります 、 01:07
など (およびバッチは 01:03
では実行されません) 、 01:10
、 01:17
など)
代わりに何をしますか?
複数のバッチを作成
単一の cron ジョブではなく、組み合わせた結果が目的のスケジュールになる複数のバッチを作成します。
たとえば、40 分ごと (00:00、00:40、01:20、02:00 など) にバッチを実行するには、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/frequent_cron_job の前回の実行が完了すると、すぐに新しい実行が開始されます。
より頻繁にバッチを開始 (ただし、条件が正しくない場合は正常に終了します)
cron 構文は制限されているため、より複雑な条件とロジックをバッチ ジョブ自体に配置することもできます。 (または、既存のバッチ ジョブのラッパー スクリプト内)。これにより、お気に入りのスクリプト言語の高度な機能を利用して、コードにコメントを付けたり、crontab エントリ自体の読みにくい構造を防ぐことができます。
seven-minute-job
を bash で すると、次のようになります:
#!/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 または 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 を使用しない
ニーズが複雑な場合は、複雑なスケジュール (複数のサーバーに分散) を実行するように設計されており、トリガー、ジョブの依存関係、エラー処理、再試行、再試行の監視などをサポートする、より高度な製品の使用を検討できます。業界用語は「エンタープライズ」です。 " ジョブのスケジューリングおよび/または "ワークロードの自動化".
解決策 5:
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 の php.ini または行 (または PHP の bash ラッパー) に以下を追加します:
- --display_startup_errors=1 を定義
- --display_errors='stderr' を定義
1 番目の設定では、'Memory oops' などの致命的なエラーを発生させ、2 番目の設定ではそれらすべてを STDERR にリダイレクトできます。すべてがログに記録されるのではなく、root のメールに送信されるため、十分に眠ることができるようになった後でのみ使用してください。