bashのif testとfindコマンドを同時に使用するには?

bashのif testとfindコマンドを同時に使用するには?

競合ログを含むディレクトリがあり、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(または[)は終了コードを返します0if終了コードは成功と解釈され、コードはその本体内で実行されます。

答え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/crashesfindはそのファイルをすべて移動します。一致するものを見つけた直後またはすぐに検索を停止する必要があります。 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複数のファイルが条件と一致する場合にコマンドが再実行されないようにします。

関連情報