web-dev-qa-db-ja.com

なぜpsの終了ステータスが異なるのですか?スクリプト内のgrep?

私はスクリプトの下で実行しています:

#!/bin/bash

ps ax  | grep -q [v]arnish
if [ $? -eq 0 ];then
        echo varnish is running...
        exit 0
else
        echo "Critical : varnish is not running "
        exit 2
fi

出力は::

[root@server ~]# sh -x check_varnish_pro.sh
+ ps ax
+ grep -q '[v]arnish'
+ '[' 0 -eq 0 ']'
+ echo varnish is running...
varnish is running...
+ exit 0

コマンドラインで同じように実行すると、終了ステータスが1になります。

[root@server ~]# ps ax  | grep -q [v]arnish; echo $?
1

ワニスがサーバーにインストールされていないような場合です。このスクリプトは、ワニスがインストールされているサーバーで正常に動作します。

スクリプトとコマンドラインを使用して実行すると、終了ステータスが異なるのはなぜですか?このスクリプトを改善するには?

11
prado

check_varnish_pro.shという名前のスクリプトを実行すると、テスト

ps ax  | grep -q [v]arnish

check_varnish_proという名前のスクリプトが実行されているため、成功します。

10
AlexP

一般に、psgrepを使用して単純なアプローチを試し、特定のプロセスが実行されているかどうかを確認することはお勧めできません。

これにはpgrepを使用する方がはるかに良いでしょう。

if pgrep "varnish" >/dev/null; then
  echo "Varnish in running"
else
  echo "Varnish is not running"
fi

pgrepのマニュアルを参照してください。一部のシステム(おそらくLinuxではない)では、grepの同じフラグに対応する-qフラグを取得します。これにより、/dev/nullにリダイレクトする必要がなくなります。また、プロセス名だけではなく、コマンドライン全体で一致を実行する-fフラグもあります。 -uを使用して、特定のユーザーに属するプロセスに一致を制限することもできます。

pgrepをインストールすると、pkillにもアクセスできるようになり、名前に基づいてプロセスに信号を送ることができます。

また、これがサービスデーモンの場合であり、UNIXシステムに情報(たとえば、稼働しているかどうか)を照会する方法がある場合、それはproperそれをチェックする方法。

Linuxではsystemctlsystemctl is-active --quiet varnishは実行中は0を返し、それ以外は3を返します)、OpenBSDではrcctlなどになります。


今あなたのスクリプトに:

スクリプトでは、ps axからの出力を解析します。この出力には、スクリプト自体の名前check_varnish_pro.shが含まれ、これには明らかに文字列varnishが含まれます。これにより、誤検知が発生します。テスト中にgrep-qフラグなしで実行した場合、これを見つけたでしょう。

#!/bin/bash
ps ax | grep '[v]arnish'

それを実行する:

$ ./check_varnish_pro.sh
31004 p1  SN+     0:00.04 /bin/bash ./check_varnish_pro.sh

もう1つの問題は、パターンで[v]を使用して、grepプロセスがgrep自体によって検出されないようにしようとした場合です。 varnishという名前のファイルまたはディレクトリが含まれているディレクトリでスクリプトまたはコマンドラインを実行すると、このアプローチは失敗します(この場合、再び誤検知が発生します)。これは、パターンが引用符で囲まれておらず、シェルがそれを使用してファイル名の展開を実行するためです。

見る:

bash-4.4$ set -x
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep '[v]arnish'
bash-4.4$ touch varnish
+ touch varnish
bash-4.4$ ps ax | grep [v]arnish
+ ps ax
+ grep varnish
91829 p2  SN+p    0:00.02 grep varnish

ファイルvarnishが存在すると、シェルは[v]arnishをファイル名varnishに置き換え、プロセステーブルのパターン(grep 処理する)。

14
Kusalananda

@ AlexPは説明します 実際に何が起こっているのかを非常に簡潔に説明していますが、重要なプロセスにpgrep/pkillを使用するの@Kusalanandaの考えは 強く非推奨より良い解決策は次のとおりです。

  • serviceが実行されているかどうかを確認しています。 systemctl status varnishdは、最新の* nixインストールでそれを処理する必要があります。
  • 不幸な状況でサービスを利用できない場合は、起動スクリプトを変更して、プロセスが終了したらすぐに問題を報告できます。

    varnish || true
    some_command_to_send_an_alert_that_the_service_has_died
    
  • または、サービスを開始するスクリプトを変更して、PIDをrecordに変更し、kill -0 "$pid"を使用して定期的に状態を確認します。
3
l0b0