ページ

2021年2月27日土曜日

Bash でプロセスの死活チェックをスマートにやる方法

プロセス名を hogehoge としたとき,

よく見かけるのはこんな感じ.
#!/bin/bash

ProcessName=hogehoge

IsActive=`ps aux | grep ${ProcessName} | grep -v grep | wc -l`

if [ ${IsActive} -gt 0 ]; then
  echo "${ProcessName} is Active."
else
  echo "${ProcessName} is Disactive."
fi

exit 0


ps aux で全てのプロセスを表示して,それをプロセス名でgrep し,ただし grep 自身もヒットしてしまうので,それを grep -v で除き,最後に wc でライン数を数える.そのライン数が0よりも大きければプロセスが存在する.と判定する.

やっていることはよく判ります.でもパイプで色々繋いだりすると,想定外の例外で引っかかることが多い...

(例えばプロセス名自体が,どこかに「grep」を含んでいる場合,この方法では検出できない)

これをもうちょっとスマートにやる方法を紹介します


まずは,pgrep コマンドを導入します.
#!/bin/bash

ProcessName=hogehoge

IsActive=`pgrep ${ProcessName} | wc -l`

if [ ${IsActive} -gt 0 ]; then
  echo "${ProcessName} is Active."
else
  echo "${ProcessName} is Disactive."
fi

exit 0

赤字の部分が変更箇所です.ps + grep というべきコマンド.pgrepを使用することで,パイプが2つ減りました.

次に,wc コマンドでライン数を数えるのをやめます.
#!/bin/bash

ProcessName=hogehoge

pgrep ${ProcessName} > /dev/null

if [ $? -eq 0 ]; then
  echo "${ProcessName} is Active."
else
  echo "${ProcessName} is Disactive."
fi

exit 0

これで,パイプもIsActive変数もなくなりました.

grep もとい,pgrep コマンドはヒットするものがあるとき,戻り値として0 を返すので,それを利用しています.(何もヒットしないときは戻り値:非ゼロ)

シェルでは基本的に変数はグローバル変数になってしまうので,定義は少ないに越したことはない.と私は考えています.

ただし,変数に代入しなくなったことで,pgrep コマンドの結果として,プロセスID が標準出力されてしまうので,それは/dev/null に捨てています.

次はこちら.$? 変数で結果を参照するのをやめます.
#!/bin/bash

ProcessName=hogehoge

if ( pgrep ${ProcessName} > /dev/null ); then
  echo "${ProcessName} is Active."
else
  echo "${ProcessName} is Disactive."
fi

exit 0

prep コマンドの実行結果(成否判定)を if 文に直接渡すようにしました.

シェルに不慣れな人にとっては,若干可読性が下がってしまうかもしれませんが,pregpの戻り値(ゼロ?or非ゼロ)を深く考える必要がなくなるのはメリットかと思います.

なお,わかりやすさのために,コマンドを()で囲っていますが,無くても同じ結果が得られます.
(厳密にはサブシェルが立ち上げられるため,全く同じという訳ではありませんが)


最後はこちら.
#!/bin/bash

ProcessName=hogehoge

pgrep ${ProcessName} > /dev/null && {
  echo "${ProcessName} is Active."
} || {
  echo "${ProcessName} is Disactive."
}

exit 0

そろそろ原型を留めていませんが,なんとなくC言語っぽく書けるので,可読性は回復したと思います.

シェルにおいて,「&&」は直前のコマンドが成功していたら実行.「||」は直前のコマンドが失敗していたら実行するので,if文の代わりにこのように記述することができる訳です.

なお,中括弧{}を普通の括弧()に変更すると,内部のコマンドは全てサブシェルで実行されることになるので,適宜使い分けると良いでしょう.

また,pgrep に似たコマンドとして,pidof というコマンドもあります.pgrep は指定したワードがプロセス名に含まれていた場合ヒットしますが,pidof の場合,プロセス名が完全一致しないとヒットしないので,より曖昧さを取り除くことができます.

0 件のコメント:

コメントを投稿