なぜpsの終了ステータスが異なるのですか?スクリプトでgrepを使用しますか?


11

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

#!/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

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

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


この種のハッカーではなく、実際のプロセス監視システムを使用してください。ご使用のオペレーティングシステムには、upstart、daemontools、systemd、launchd、または他の多くの選択肢の1つである、障害時に自動的に再起動したいデーモンを確実に再起動する組み込みの方法があります。それらはすべて、この種の手巻きハッカーよりも堅牢で機能的です。
Charles Duffy 2017年

回答:


10

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

ps ax  | grep -q [v]arnish

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


14

一般的に、と単純なアプローチをしようとする悪い考えだpsgrep、与えられたプロセスが実行されているかどうかを決定しようとします。

あなたはpgrepこれのために使う方がはるかに良いでしょう:

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

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

インストールpgrepもすることは、あなたがにアクセスすることができますpkillあなたは、その名前に基づいて信号処理することを可能にします。

また、これがサービスデーモンであり、Unixシステムに情報を問い合わせる方法がある場合(たとえば、稼働しているかどうか)、それが適切な方法です。

Linuxの場合systemctlsystemctl is-active --quiet varnish実行している場合は0を返し、それ以外の場合は3を返します)、OpenBSDの場合rcctlなどです。


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

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

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

それを実行する:

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

もう1つの問題は、パターンで使用grepするgrepことにより、プロセスがそれ自体で検出されないように「隠そう」としていることです[v]。その方法でファイルまたはディレクトリが指定さ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プロセス)のパターンにヒットします。


4
すべてが「Linuxランド内」のファイルであるためです。
zee

@ z_-接続方法はわかりませんが、これは非Linux Unicesでも当てはまります。
クサラナナンダ

4
grepプロセスだけでなく、名前check_varnish_pro.shが付けられているスクリプトも要因です。
TNW 2017年

@TNW私は最初はそれを発見しませんでしたが、あなたは正しいです。追加します
。– Kusalananda

3

@AlexPは実際に何が起こっているのかを非常に簡潔に説明していますが、重要なプロセスに/ 使用するpgreppkillという@Kusalanandaの考え強く推奨されていませんより良いソリューションは次のとおりです。

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

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

私は同意します、私は問題のシェルスクリプトの側面に対処していただけです。ただし、systemctlほとんどの場合、Linux(AFAIK)でのみ使用でき、最近のUnixライクなシステムでは使用できません。
クサラナンダ

元の質問には「linux」というタグがありました。@muruによって削除された理由がわかりません。
l0b0

l0b0に感謝します。「なぜ」と「改善方法」の2つの質問がありました。@AlexPの答えは私の最初の質問を解決しました、そしてあなたの答えは2番目の質問のためのより良い解決策です。しかし、クサラナンダはこれに関連することを説明します。これは、同様の問題を抱えている人々にとって役立つと思います。だから私は今、どちらを答えとして受け入れるか混乱しています。
プラド2017年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.