Debian 8.1 で私は使用しています吹くstackoverflow.comウェブサイトにアクセスできるかどうかを検出する機能:
(エコ>/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "スタックオーバーフローにアクセスできません。"
sh
これはBashにのみ適用され、.defaultシェルには影響しませんcron
。
意図的にスクリプトを試してみると、次のような結果がsh
得られます。
$ /bin/sh: 1: cannot create /dev/tcp/stackoverflow.com/80: Directory nonexistent
SHELL
したがって、以下をプライベートcrontab(viaに設定しない/bin/bash
)に入れると、crontab -e
スクリプトは1分ごとに実行されるので、上記のエラーを電子メールごとに1分に1回送信したいと思います。
* * * * * (echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "Stackoverflowにアクセスできません。"
実際には、期待どおりに/var/log/syslog
このアイテムが毎分実行されていることがわかります。
#sudo grep スタックオーバーフロー /var/log/syslog 8月24日18:58:01ローカルホスト CRON[13719]: (mat) CMD ((echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "stackoverflow にアクセスできません。") 8月24日18:59:01ローカルホスト CRON[13723]: (mat) CMD ((echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "stackoverflow にアクセスできません。") 8月24日19:00:01ローカルホスト CRON[13727]: (mat) CMD ((echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "stackoverflow にアクセスできません。") ...
このコマンドは過去2時間で120回以上実行され、出力をwc -l
。
しかし、、これらの120以上のシェルコマンド(繰り返し:シェルコマンドのペアが無効です/bin/sh
)が実行されたため、次の結果のみが得られます。サムEメール:
最初は19:10:01、2番目は20:15:01、3番目は20:57:01です.
3つのメッセージの内容はすべて期待どおりに正しく読み取られ、(意図的に)互換性のないシェルでスクリプトを実行したときに予想されるエラーメッセージも正しく含まれていました。たとえば、私が受け取った2番目のEメールは次のようになりました(残りの2つのEメールはほぼ同じです)。
~から[Eメール保護] 2015年8月24日月曜日20:15:01 から:[Eメール保護](クレーンデーモン) 到着する:[Eメール保護] トピック: Cron (echo >/dev/tcp/stackoverflow.com/80)&>/dev/null || echo "Stackoverflowにアクセスできません。" ... /bin/sh: 1: /dev/tcp/stackoverflow.com/80 を生成できません: ディレクトリが存在しません`
/var/log/mail.log
から送信された3つの電子メールは次のとおりです。ただここ数時間で送受信されたメッセージです。
もしそうなら、間違ったスクリプトによって生成された上記の出力のためにcronが受信すると予想される100以上の追加の電子メールはどこにありますか?
結論として:
- このシステムでは、メールが正しく設定されており、問題なくメールを送受信できます
/usr/bin/sendmail
。 - Cronは正しく設定され、期待どおりにタスクを認識し、設定された時間に正確に実行します。私は他の多くのタスクと予約オプションを試してみましたが、cronは期待どおりに正確に実行しました。
- スクリプトいつも出力を作成するので(下記参照)、cronが呼び出すたびに出力を電子メールで送信することを期待しています。
- 結果は時々私に郵送され、ほとんどの場合無視されます。
上記の観察結果につながる明らかなエラーを解決する方法はいくつかあります。
SHELL=/bin/bash
私はそうすることができますcrontab
。heartbeat.sh
withを作成して#!/bin/bash
呼び出すことができます。/bin/bash -c ...
insideを使用してスクリプトを呼び出すことができますcrontab
。- ちょっと待ってください。これらすべてが
sh
。
ただし、どちらもこの問題の重要な問題を解決しません。つまり、この場合、cron
スクリプトでさえも安定してメールを送信できないということです。いつも出力を生成します。
私はスクリプトが常にwrong.sh
次のものを生成して出力を生成することを確認しました。故意に不適切なシェルを使用すると、表示されるのと同じエラーが/bin/sh
発生します。)cron
#!/bin/sh (echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "Stackoverflowにアクセスできません。"
これでスクリプト呼び出しを繰り返して、完了する項目があるかどうかを確認できます。いいえ出力を生成します。使用吹く:
$ trueの場合; do [[ -n $(./wrong.sh 2>&1 ) ]] echo $?;
何千もの呼び出しにもかかわらず、出力を生成せずにスクリプトが完了する状況を再現することはできません。
このように予測できない行動が現れるのはなぜでしょうか。誰でもこれを再現できますか?私には、cronがスクリプトの出力を見逃す可能性がある競合条件がある可能性があるようです。おそらく、ほとんどの場合、エラーがシェル自体で発生する状況に関連している可能性があります。ありがとうございます!
答え1
&
追加のテストをしてみると結果がめちゃくちゃになりそうです。指摘した通りです&>/dev/null
。強く打つ文法、いいえシェン通事論。その結果、sh
サブシェルが作成され、背景に設定されます。もちろん、サブシェルはecho
stderrを生成しますが、私の理論は次のようになります。
- cronはサブシェルのstderrをキャプチャしません。
- サブシェルの背景は常に正常に完了します
|| echo ...
。
...クローンジョブで出力が発生しないため、メールはありません。 vixie-cronのソースコードを読むと、ジョブのstderrとstdoutがcronによってキャプチャされますが、サブシェルによって確実に失われるようです。
/bin/sh環境で直接テストしてみてください(ここに「bar」というファイルがないとします)。
(grep foo bar) &
echo $?
答え2
次のcrontabを使用してUbuntu 15.04で動作を再現できます。
* * * * * { echo job 0; } & sleep 5
* * * * * { echo job 1; } &
* * * * * { sleep 5; echo job 2; } &
job 0
毎分、cronから次の内容を含むEメールを受け取ります。job 1
時々(最近10分間5〜6回)、なしjob 2
。
したがって、cronは子プロセスが終了するのを待ってから、その時点で吸収できるすべてのstdout / stderr出力を含む電子メールを送信するようです。孤立した孫プロセスの遅延出力は、単に削除されます。
答え3
上記の説明に加えて、もう少し簡単な説明があるかもしれません。
すべてのシェルは、作業を実行する前にコマンドラインを拡張/処理することを覚えておいてください。したがってsh
、「&」に展開すると、コマンドラインが終了し、それをバックグラウンドに入れようとし(デフォルトでは低い優先順位)、リダイレクトされた内容によってはstdin / stdout / stderrが正しく割り当てられません。したがって、「競合条件」は、シェルが線を処理する速度に依存する可能性があり、これは明らかにシステムの負荷(およびその後にシステムと対話する方法cron
)によって異なります。