クラッシュログのあるディレクトリがあり、findコマンドに基づくbashスクリプトで条件ステートメントを使用したいと思います。
ログファイルは次の形式で保存されます。
/var/log/crashes/app-2012-08-28.log
/var/log/crashes/otherapp-2012-08-28.log
過去5分間に変更された特定のアプリのクラッシュログが存在する場合にのみ、ifステートメントでtrueを返します。私が使用するfind
コマンドは次のとおりです。
find /var/log/crashes -name app-\*\.log -mmin -5
これをif
ステートメントに適切に組み込む方法がわかりません。私はこれがうまくいくと思います:
if [ test `find /var/log/crashes -name app-\*\.log -mmin -5` ] then
service myapp restart
fi
不明な点がいくつかあります。
test
ディレクティブが必要ですか、それともfindコマンドの結果に対して直接処理するだけですか、またはfind... | wc -l
代わりに行数を取得するには?test
は、コマンドが返す戻りコードに対してテストするためのものですか?そして、それらは目に見えない-stdout
/stderr
の外では?私はman
ページを読みましたが、test
をいつ使用し、どのようにデバッグするかについてはまだはっきりしていません。_[
_とtest
は同義語です(ただし、_[
_は_]
_が必要)を除くため、_[ test
_は使用しないでください。
_[ -x /bin/cat ] && echo 'cat is executable'
test -x /bin/cat && echo 'cat is executable'
_
test
は、条件が真の場合はゼロの終了ステータスを返し、そうでない場合はゼロ以外を返します。これを実際に任意のプログラムに置き換えて、終了ステータスを確認できます。0は成功を示し、0以外は失敗を示します。
_# echoes "command succeeded" because echo rarely fails
if /bin/echo hi; then echo 'command succeeded'; else echo 'command failed'; fi
# echoes "command failed" because rmdir requires an argument
if /bin/rmdir; then echo 'command succeeded'; else echo 'command failed'; fi
_
ただし、上記の例はすべてプログラムの終了ステータスに対してのみテストし、プログラムの出力は無視します。
find
の場合、出力が生成されたかどうかをテストする必要があります。 _-n
_空でない文字列かどうかをテストします。
_if [[ -n $(find /var/log/crashes -name "app-*.log" -mmin -5) ]]
then
service myapp restart
fi
_
テスト引数の完全なリストは、bash
コマンドラインで_help test
_を呼び出すことで利用できます。
bash
を使用している場合(sh
ではなく)、_[[ condition ]]
_を使用できます。これは、条件にスペースまたはその他の特殊なケースがある場合に、より予測どおりに動作します。それ以外は、通常、_[ condition ]
_を使用する場合と同じです。この例では、可能な限り_[[ condition ]]
_を使用しています。
また、_`command`
_を$(command)
に変更しました。これも通常は同じように動作しますが、ネストされたコマンドの方が適しています。
エラーがなければfind
は正常に終了するため、その終了ステータスを頼りにファイルが見つかったかどうかを知ることはできません。しかし、言ったように、見つかったファイルの数を数え、その数をテストすることができます。
これは次のようなものです。
if [ $(find /var/log/crashes -name 'app-*.log' -mmin -5 | wc -l) -gt 0 ]; then
...
fi
test
(別名[
)はコマンドのエラーコードをチェックしません。テストを実行するための特別な構文があり、テストが成功した場合はエラーコード0で終了します。またはそれ以外の場合は1。渡されたコマンドのエラーコードをチェックし、それに基づいて本体を実行するのはif
です。
man test
(またはbash
を使用している場合はhelp test
)とhelp if
(同上)を参照してください。
この場合、wc -l
は数値を出力します。 test
のオプション-gt
を使用して、その数が0
より大きいかどうかをテストします。ある場合、test
(または[
)は終了コード0
を返します。 if
はその終了コードを成功と解釈し、コードを本体内で実行します。
これは
if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5)" ]; then
または
if test -n "$(find /var/log/crashes -name app-\*\.log -mmin -5)"; then
コマンドtest
と[ … ]
はまったく同じ意味です。唯一の違いは、その名前と、[
が最後の引数として終了]
を必要とするという事実です。いつものように、コマンド置換を二重引用符で囲みます。二重引用符を使用しないと、find
コマンドの出力が単語に分割されます。一致するファイルが複数ある場合(およびそこにある場合)、構文エラーが発生します引数がない場合、[ -n ]
はtrueですが、[ -n "" ]
はfalseです)。
Ksh、bash、zshでは、ashでは使用できませんが、[[ … ]]
を使用することもできます。[
は通常のコマンドですが、[[ … ]]
は別の構文解析構文です。 [[ … ]]
内に二重引用符は必要ありません(ただし、害はありません)。コマンドの後に;
が必要です。
if [[ -n $(find /var/log/crashes -name app-\*\.log -mmin -5) ]]; then
これは潜在的に非効率になる可能性があります。/var/log/crashes
に多くのファイルがある場合、findはそれらすべてを調査します。一致が見つかるとすぐに、またはすぐ後にfindを停止する必要があります。 GNU find(非組み込みLinux、Cygwin))では、-quit
プライマリを使用します。
if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print -quit)" ]; then
他のシステムでは、find
をhead
にパイプして、少なくとも最初の一致の直後に終了します(findは壊れたパイプで終了します)。
if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print | head -n 1)" ]; then
(head
コマンドでサポートされている場合は、head -c 1
を使用できます。)
または、zshを使用します。
crash_files=(/var/log/crashes/**/app-*.log(mm-5[1]))
if (($#crash_files)); then
これはうまくいくはずです
if find /var/log/crashes -name 'app-\*\.log' -mmin -5 | read
then
service myapp restart
fi
find /var/log/crashes -name app-\*\.log -mmin -5 -exec service myapp restart ';' -quit
ここで適切なソリューションです。
-exec service myapp restart ';'
を指定すると、シェルが何かを解釈する必要はなく、直接実行したいコマンドがfind
によって呼び出されます。
-quit
を指定すると、コマンドの処理後にfind
が終了し、基準に一致するファイルが複数ある場合にコマンドが再度実行されるのを防ぎます。