競合ログを含むディレクトリがあり、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
行数を取得できますか? - この質問に100%答える必要はありませんが、
test
コマンドから返された戻りコードをテストするためのものですか?見えないか。内部stdout
/外部stderr
?ページを読みman
ましたが、いつ使用しtest
てデバッグするかはまだ明確ではありません。
答え1
[
とtest
同義語([
requireを除く]
)なので、以下を使用したくありません[ test
。
[ -x /bin/cat ] && echo 'cat is executable'
test -x /bin/cat && echo 'cat is executable'
test
条件が true の場合は終了状態 0 を返し、そうでない場合は 0 以外の値を返します。これは実際に終了ステータスを確認するプログラムに置き換えることができます。ここで、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
help test
テストパラメータの完全なリストは、コマンドラインから呼び出すことで取得できますbash
。
これは、条件にスペースやその他の特殊なケースがある場合、より予測可能に動作するbash
(代わりにsh
)を使用すると機能します。[[ condition ]]
それ以外の場合は、通常を使用するのと同じです[ condition ]
。この例ではこれを使用し、[[ condition ]]
可能な限り使用します。
また、一般的に同様に動作しますが、入れ子になったコマンドをより良いに`command`
変更しました。$(command)
答え2
find
エラーなしで正常に終了するため、終了ステータスに依存してファイルが見つかったことを確認できません。しかし、あなたが言ったように、どれだけのファイルを見つけたかを計算し、その数をテストすることができます。
次のようになります。
if [ $(find /var/log/crashes -name 'app-*.log' -mmin -5 | wc -l) -gt 0 ]; then
...
fi
test
(別名[
)はコマンドのエラーコードをチェックせず、これをテストする特別な構文があり、テストが成功した場合はエラーコード0で終了し、それ以外の場合は1で終了します。if
渡したコマンドのエラーコードを確認し、それに基づいて本文を実行します。
man test
(またはhelp test
を使用している場合bash
)とhelp if
(ibid。)を参照してください。
この場合、wc -l
数字が出力されます。test
■オプションを使用して、-gt
数値が大きいかどうかをテストします0
。その場合test
(または[
)は終了コードを返します0
。if
終了コードは成功と解釈され、コードはその本体内で実行されます。
答え3
これは〜になります
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
です。[ … ]
唯一の違いは、名前と最後のパラメータに[
endが必要であることです。]
いつものように、コマンドの置き換えには二重引用符を使用してください。それ以外の場合は、コマンドの出力がfind
単語に分割され、一致するファイルが複数ある場合は構文エラーが発生します(引数がない場合はtrue [ -n ]
)。しかし、欲しい[ -n "" ]
ものは間違っています。 。
ksh、bash、zshでは、ash以外の[[ … ]]
構文解析ルールを使用して使用することもできます。これは[
一般的なコマンドです[[ … ]]
が、構文解析構造が異なります。内部に二重引用符を使用する必要はありません[[ … ]]
(有害ではありませんが)。;
コマンドの後に続くものがまだ必要です。
if [[ -n $(find /var/log/crashes -name app-\*\.log -mmin -5) ]]; then
これは非効率的である可能性があります。にファイルが多い場合、/var/log/crashes
findはそのファイルをすべて移動します。一致するものを見つけた直後またはすぐに検索を停止する必要があります。 GNU find (非埋め込み Linux, Cygwin) では基本-quit
。
if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print -quit)" ]; then
他のシステムでは、パイプのfind
入り口はhead
少なくとも最初の一致の直後に終了します(パイプが破損していることを発見した場合は死にます)。
if [ -n "$(find /var/log/crashes -name app-\*\.log -mmin -5 -print | head -n 1)" ]; then
head -c 1
(コマンドがサポートしている場合はhead
機能します。)
またはzshを使用してください。
crash_files=(/var/log/crashes/**/app-*.log(mm-5[1]))
if (($#crash_files)); then
答え4
find /var/log/crashes -name app-\*\.log -mmin -5 -exec service myapp restart ';' -quit
適切なソリューションです。
-exec service myapp restart ';'
find
シェルが何も解釈せずに直接実行したいコマンドが呼び出されるようにします。
-quit
処理後にコマンドを終了させ、find
複数のファイルが条件と一致する場合にコマンドが再実行されないようにします。