シェル/grep 同名プロセスのカウント

このQ&Aのポイント
  • ターミナルで複数のbashプロセスの数を調べる方法を教えてください。
  • lessプロセスの数を調べると、正しい数値が返ってきますが、自作シェルスクリプトの場合は正しい数値よりも1つ多くなります。
  • 間違った操作をしているのかどうか、理由を教えてください。
回答を見る
  • ベストアンサー

シェル/grep 同名プロセスのカウント

例えば、ターミナルをいくつか起動して、bashが動いている数を調べるのに、 $ cnt=`ps ax | grep 'bash' | grep -v -c 'grep'` $ echo $cnt とすると、あるべき数より1つ多い数値がcntに入っています。 $ ps ax | grep 'bash' | grep -v -c 'grep' で出力される数に1を足した数値です。 一方、lessをいくつか起動して、上記の'bash'を'less'に代えると正しい数値が返ります。 上記の'bash'を自作シェルスクリプト'mycmd'に代えると、cntにはあるべき数より1つ多い数値が入ります。 間違った操作をしているのかもしれませんが、これはどういう事情によるものでしょうか。 2014年8月7日

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4848/10261)
回答No.3

>の場合、grepが検索しているのは'bash'ではなく'test.sh'ですが、サブシェルを表すpsコマンドの出力に'test.sh'という文字列が含まれているのでしょうか。 そうですね。含まれています。 パイプを流れる文字列を途中で見てみましょう。 cmd=`basename $0` cnt=`ps ax | grep $cmd | tee /dev/tty | grep -v -c grep` echo $cnt のようにしてみてください。grep $cmd の結果が、端末(/dev/tty)に表示されます。 あるいは、grep 前の ps の出力を見た方が良いかもしれない。 cnt=`ps axf | tee /dev/tty | grep $cmd | grep -v -c grep` とか。 サブシェルを使わなければ、数は増えません。 cmd=`basename $0` ps axf | tee /dev/tty | grep $cmd | grep -v -c grep > /tmp/1 read cnt < /tmp/1 echo $cnt

RASUM2
質問者

お礼

notnot様、ありがとうございます。 サブシェルのpsコマンドの出力がわかりました。 teeコマンドの使い方に感激しました。 2014年8月9日

その他の回答 (2)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

なんの不思議もありません。 バッククオートや$() でコマンドを実行するときに、 (コマンドラインを入力した)bashを親とした子プロセスが作られ、そこで実行します。 その時に、 パイプラインを使った場合等では、その処理のために、シェルが実行されます(サブシェルと言ったりします) cnt=`ps ax | grep 'bash' | grep -v -c 'grep'` だと、このコマンドラインを入力したbashを親として bash -c "ps ax | grep 'bash' | grep -v -c 'grep'" が実行されます。このbashは、コマンドライン入力したbashとは別のプロセスです。 スクリプトを実行するときも同じです。 test.sh 等と実行したとき、test.shの中身を実行するのは、コマンドライン入力した親のbashではなく、そこから呼び出された子のbashです。 この点は、スクリプト初心者が陥りやすい罠になっています。 環境設定用に #env.sh export TEST_PATH=/foo/bar というスクリプトを作ったとします。 これを使おうと、 env.sh と実行しても、 export~が実行されるのは、子シェルです。環境変数は、親→子には引き継がれますが、逆には対応できません。 親シェルの方は、この設定が実行前のままになります。 親シェルで実行するには、 sourceを使う必要があります。 このあたりは、Windowsのバッチファイルとは違うので注意しましょう。

RASUM2
質問者

補足

kmee様、丁寧な回答をありがとうございます。 理解力がなくてなさけないですが、 $ cat test.sh   cmd=`basename $0`   cnt=`ps ax | grep $cmd | grep -v -c 'grep'`   echo $cnt の場合、grepが検索しているのは'bash'ではなく'test.sh'ですが、サブシェルを表すpsコマンドの出力に'test.sh'という文字列が含まれているのでしょうか。 2014年8月8日

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

バッククオートで「サブシェル」を起動してるからでは?

RASUM2
質問者

補足

kmee様、ありがとうございます。 自作のスクリプトを走らせて検索した場合も1つ多い数となるのが不思議です。この場合はlessと同じように正しい数が返ってくると思うのですが。 2014年8月8日

関連するQ&A

  • シェルについて

    以下のような「プロセスをkillするシェル」を作成しています。 そこで質問なのですが、プロセスが死んだら繰り返しを抜ける ようにしたいと考えているのですが、どのようにすれば実現できるのか 分かりません。 どなたかご存知の方がいらっしゃれば教えていただきたいです。 申し訳ありませんが、宜しくお願いいたします。 #!/bin/csh # 変数定義 set cnt = 3 #リトライカウンタ set i = 1 # ループカウンタ #aaaをkill while ( $i <= $cnt ) ps -ef | grep -v grep | grep aaa | \ nawk '{if(match($NF,"aaa") == 1){system("kill " $2);print "kill: " $2}}' ps -ef | grep -v grep | grep aaa| \ nawk '{if(match($NF,"aaa") == 1){system("kill -9 " $2);print "kill: " $2}}' @ i = $i + 1 end

  • 実行中のプロセス数をカウントしたい

    ネットで以下コマンドを見つけて実行しました。 ps -ef | grep -v grep | grep httpd 実行結果は/usr/sbin/htpdが9行表示 この9行をカウントしたい為、 ネットで以下コマンドを見つけて実行しました。 ps -ef | grep -v grep | grep httpd | wc 実行結果は『9 72 576』が表示 上記の結果で9のみを表示させるコマンドがあれば 教えていただけないでしょうか。 また、実際にカウントしたいプロセスは以下例のように 半角スペースと()をふくんでおり 上記httpdのようにうまくいきませんでした。 例:test (rei) 半角スペースと()を含んだプロセス数をカウントするコマンドがあれば 教えていただけないでしょうか。

  • シェルの変数の動作についての質問

    solaris8上で、シェルから別のシェルを子プロセスを動作させて その子プロセスが終了したかを判定するシェルを作成しました。 そのシェルの抜粋は下記のようになっています。 ---------------------------------------------------- "コマンド実行" & PID=$! i=0 ERR_FLG=1 echo " PID="$PID >> tmp.txt   ・・・・(1) while [ 1 ] do   if [ `ps -ef | grep $PID | grep -v grep | wc | awk '{print $1}'` -eq 0 ]; then     ERR_FLG=0     break   fi   "終了条件を満たしたかを確認するサブルーチン"   if [ $? -eq 1 ]; then     echo "Time out" >> tmp.txt     break   fi   i=`expr $i + 1 `   sleep 10 done echo `ps -ef | grep $PID | grep -v grep` >> tmp.txt ・・・・(2) ---------------------------------------------------- 殆どの場合問題なく動作しているのですが、 ごく稀に、(1)と(2)で取得した$PIDの値が異なるという現象が起きます。 当然サブルーチン上で、PIDを書換する処理もありません。 どのような状況の時に、現象が起きるかもはっきりしていません。 この現象の回避方法が判る方がおられましたら御教示の程、 宜しくお願いします。

  • 想定外の戻り値に付いて

    Linux系OSのシェルスクリプトについて質問です。 スクリプトの内容としては各主要サービスの起動と停止を行う内容になります。 ここでお伺いしたい内容はスクリプトの途中でサービスが起動しているかどうか、grepの戻り値によって処理を変更する場合にgrepの戻り値がどうにもおかしい場合、どのような原因が考えられるか、ということです。 【スクリプト内容(抜粋)】 #!/bin/bash ---中略--- echo "Apache2起動前確認" | tee -a ${LOG} ps -ef | grep apache2 | grep -v "grep" > /dev/null if [ $? == 0 ]; then ---省略--- 上記の内容はapache2を起動する際、apache2が起動していれば処理を中止する内容の一部ですが、当然起動していればpsコマンドで内容が出るのでgrepの戻り値は0になり、「then」の内容が実施されます。 これはこれで完成されているので問題なく稼動します。 しかしこれとまったく同じ内容で、apache2をmysqlに変更したものが問題でこちらが正常に動作しないのです。 【スクリプト内容(抜粋)】 #!/bin/bash ---中略--- echo "MySQL起動前確認" | tee -a ${LOG} ps -ef | grep mysql | grep -v "grep" > /dev/null if [ $? == 0 ]; then ---省略--- これだとなぜか停止しているときに戻り値が「0」、起動しているときに戻り値が「1」になってしまいます。 ifとpsの間に「echo $?」をかませてみても想定外の戻り値がセットされているためif文そのものには間違いはありません。 また、コマンドラインで「ps -ef | grep mysql | grep -v "grep" > /dev/null ; echo $?」を 実施しても戻り値は「1」に(停止している場合)なるのですが、スクリプト上では戻り値「0」がセットされるようです。 何ゆえこのような意図しない動作をするのか考えてもわかりません。 apache2の場合だと正常に動くだけになおわかりません。 因みに停止しているとき、起動しているときでまったく逆の戻り値がそれぞれ返ってきているようです。 どなたか原因がわかる人は教えてください、宜しくお願いいたします。

  • シェル関数引数のスペース文字列をgrepに

    下記のシェル関数 arg_space() 内で、grepを使いたいのですが。 'aaa bbb' などのスペースを含む文字列を引数として渡すとスペース後の文字列がファイル名と 認識されてしまいます。 -- arg_space.sh -- #!/bin/bash CHK_STR='aaa bbb' FILE_NAME='data/aaa.txt' function arg_space() { return `grep -c $1 $2` } arg_space $CHK_STR $FILE_NAME if [ $? -ge 1 ]; then echo 'Match !!' else echo 'No match.' fi exit 0 ------------------ ]# ./arg_space.sh grep: bbb: No such file or directory Match !! スペース文字を、grep に区切り文字として認識させないようにする 方法を教えて 頂けないでしょうか。 -- data/aaa.txt -- aaa bbb ccc ddd ---------------

  • シェルスクリプト間で排他をとりたい

    環境 linux(redhat) 使用シェル bash シェルスクリプトAとシェルスクリプトBを作成し、 シェルスクリプトAが動作している間は、シェルスクリプトBの動作を禁止したいと考えています。 例えば、シェルスクリプトAが起動している状態で、シェルスクリプトBが起動されたとき、シェルスクリプトBは、シェルスクリプトAが起動していることを検知して、自発的に処理を終了するようにしたいと考えています。 上記のような仕組みをシェルスクリプトで実現可能でしょうか? 基本的には、シェルスクリプトの先頭で、ある資源のロックを行い、終了時にロックの解放ができれば、その仕組みは実現可能と考えています。 (シェルの異常終了時は、ロックが自動的に解放されることが望ましい) 上記のようなことをシェル(bash)で実現可能でしょうか。 bash単独での方法、もしくはbashからperl,C言語作成の実行モジュールを呼び出す方法でもかまいません。 (ちなみにperl(もしくはC言語作成のモジュール)単独では実現可能なことはわかっています)

  • Emacsのシェルモードでワイルドカードが使えない

    こんにちは。 Emacsは、Gnu Emacs for Windows 23.4 を使っています。 シェルモードのシェルには、cygwinのbashを使っているのですが、 bashで使えるはずのワイルドカードが、いくつか使えなくて、困っています。 bashのワイルドカードで、使えないものは、以下の通りです。 ?(pattern) 与えられたパターンが 0 回または 1 回現われるとマッチします。 *(pattern) 与えられたパターンが 0 回以上現われるとマッチします。 +(pattern) 与えられたパターンが 1 回以上現われるとマッチします。 !(pattern) 与えられたパターンいずれにも含まれないもの全てにマッチします。 これらのワイルドカードは、ktermなどの上では、きちんと使えます。 例えばkterm上で、 echo !(*.c) と打てば、.cで終わらないファイル名を持つ、ファイルの一覧が表示されます。 ところが、Emacsのシェルモードで、同じように echo !(*.c) と打つと、 emacs "bash: !: event not found" と表示されます。 同様に、 echo *(.c) と打った場合、 bash: 期待してない token `(' のあたりにシンタックスエラー と表示されます。 どうすれば、こういったワイルドカードを、シェルモードで使う事ができるのでしょうか? 何か御存じの方がいらっしゃれば、是非、情報を提供して頂きたく思います。 では、よろしくお願い致します。

  • system関数でのシェル起動について

    system関数でシェルコマンドを発行しているC言語のプログラムがあります。 起動されるシェルコマンド(Cシェル)は2重起動防止のため以下の様にコマンド名をgrepしてPIDを取得し、2つ以上あると2重起動と見なしてコマンドを終了させています。 ps -aef | grep 自身のコマンド名 | grep -v grep ~ この時1回目の起動であるのに2重起動チェックに引っかかってしまいコマンドが実行されませんでした。 デバッグしたところ"csh コマンド名"のPIDとは別に一瞬"sh -c コマンド名"というプロセスがあってそれのPIDと合わせて2つに起動していると見なしていました。 調べたところsystem関数はsh経由(sh -c)でコマンドを実行するためだと言う事が分かり納得出来ました。 また元々バックグラウンドで起動させたいコマンドだったので以下の様に"&"を付与したところ2重起動チェックには引っかからなくなりました。 system("コマンド名 &") バックグラウンド起動させても2重起動チェックで弾かれれば納得出来るのですが、通常の起動と何が違うか分からずに釈然としません。 良く分かりませんが、通常起動だとオーバーヘッドで実行に時間がかかりチェックで弾かれるけど、バックグラウンドだと一瞬で起動されてたまたま上手く行った様に見えるだけだったりするなどなのでしょうか?? もしご存知の方がいらっしゃいましたらご教示頂けると幸いです。

  • bash:あるプロセスをkillするスクリプト

    こんにちは。 RedHat9を使っています。 bashシェルで、コマンドの実行結果を変数にわたすには、どうしたらいいですか? mpg123でmp3を聞いています。 ターミナルからCtrl+Cを2回入力するのではなしに、スクリプトを走らせるだけで実行をとめたいです。 ps -A | grep 'mpg123' の実行結果を変数に入れて、killコマンドの引数にその変数をわたせばいいんじゃないかと思ったんですが。 すみません、よろしくおねがいします。

  • シェルの実行履歴

    はじめまして。 会社にてBTSの管理をすることになったのですが、 システムが落ちた際に自動で起動するシェルが動いていない様で困っています。 仕組みとしては checkシェルが1分ごとに動き監視→落ちていると判断すると、restartシェルが動く という感じです。 ですが朝来ると落ちていることがたまにあり、 たぶんどこかのシェルが正しく動いてないんじゃないか?と思っています。 そこでまず、 checkシェルが正しく動いているのか? を調べようと思いシェルの実行履歴とか見れないのかな? と思い探していたのですが、うまく見つからず困っています。 一応checkシェルも記載いたします。 個人的に怪しいなと思っている箇所は、[怪しい] と記載されている辺りです。 これを作成した人が何も情報を残さずにやめてしまって、どういう根拠で条件を設定しているのか不明なんです。 ---------------------------------------------- #!/bin/sh tomcat_home=/usr/local/scarab-1.0-b20/tomcat chk_log=$tomcat_home/logs/catalina.out while true do btspid=`ps ax | grep "\[java\]" | awk '{print $1}'` [怪しい] isAlive=`tail -n 261 $chk_log | grep OutOfMemoryError | wc -l` if [ $isAlive -lt 3 ]; then echo "scarab is still alive, error count = $isAlive : pid = $btspid" else echo "scarab is dead... errot count = $isAlive ; pid = $btspid" ~/restart.sh # break fi sleep 60 done ------------------------------------

専門家に質問してみよう