web-dev-qa-db-ja.com

私のpsに侵入するgrep

私がいくつかのプロセスをチェックしているとき、私は通常書く

ps aux | grep myprocess

そして時々の出力を取得します

eimantas 11998  0.0  0.0   8816   740 pts/0    S+   07:45   0:00 grep myprocess

プロセスが実行されていない場合。

psコマンドの出力を除外すると、なぜgrepがプロセスのリストに含まれるのか、本当に疑問に思いますafterpsが実行されましたか?

5
Eimantas

この動作は完全に正常です。これは、bashがパイプの使用を管理する方法が原因です。

pipeは pipe syscallを使用してbashによって実装されます。その呼び出しの後、bashはフォークし、標準入力( ファイル記述子 )を適切なプロセスからの入力(grep)で置き換えます。メインのbashプロセスは、別のフォークを作成し、標準入力の代わりにFIFOの出力記述子を渡し( ファイル記述1 )、左のコマンドを起動します。

psユーティリティはgrepコマンドの後に起動されるため、出力で確認できます。

確信が持てない場合は、set -xを使用してコマンドトレースを有効にできます。例えば:

+ ps aux
+ grep --color=auto grep
+ grep --color=auto systemd
alexises  1094  0.0  0.8   6212  2196 pts/0    S+   09:30   0:00 grep --color=auto systemd

詳細については、基本的なcシェルのこの部分を確認できます。 http://www.cs.loyola.edu/~jglenn/702/S2005/Examples/dup2.html

12
alexises

プロセスの存在のみに関心がある場合は、この動作を示さないpgrepを使用します。例:

$ pgrep myprocess
1900

その他の場合(詳細に興味がある場合)、通常は| grep -v grepを追加して、grep行を破棄します。例:

$ ps -ef | grep myprocess| grep -v grep
8
tonioc

pipe;のようには動作しません。両方のプロセスを一緒に開始します。そのため、grepコマンドも表示されました。したがって、ps aux | grep myprocessを指定すると、ps auxにはgrep myprocessが含まれるため、grepはそれを出力に含めます。

これを確認するために、テストサーバーで次のように2つのddコマンドを実行しました。

[sreeraj@server ~]$ dd if=/dev/urandom of=/home/sreeraj/myfile1 bs=1M count=1024 | dd  if=/dev/urandom of=/home/sreeraj/myfile2 bs=1M count=1024

そして、ddプロセスをチェックしたところ、両方が同時に開始されたことが示されています(2:55分が経過したという列を見てください):

[sreeraj@server ~]$ ps aux | grep 'dd if'
sreeraj  14891  100  0.2   5376  1416 pts/0    R+   11:56   2:55 dd if=/dev/urandom of=/home/sreeraj/myfile1 bs=1M count=1024
sreeraj  14892  100  0.2   5376  1412 pts/0    R+   11:56   2:55 dd if=/dev/urandom of=/home/sreeraj/myfile2 bs=1M count=1024
sreeraj  14936  0.0  0.1   9032   672 pts/1    S+   11:59   0:00 grep --color=auto dd if
[sreeraj@server ~]$

ここで、grepを出力から除外する場合は、regexを使用します。結果からgrepを除外します:

ps aux | grep "[m]yprocess"

たとえば、httpdプロセスを探している場合は、次を使用します。

ps aux | grep "[h]ttpd"

ただし、より信頼性の高いpgrep -aを使用することをお勧めします。

[sreeraj@server ~]$ pgrep -a httpd
8507 /usr/sbin/httpd -DFOREGROUND
8509 /usr/sbin/httpd -DFOREGROUND
8510 /usr/sbin/httpd -DFOREGROUND
8511 /usr/sbin/httpd -DFOREGROUND
8513 /usr/sbin/httpd -DFOREGROUND
8529 /usr/sbin/httpd -DFOREGROUND
[sreeraj@server ~]$
6
Sree

あなたは正しいです、それはそれがどのように機能するかではありません。シェルは、パイプラインの最初のプロセスが終了するのを待たずに、次のプロセスを開始します。それはそれらすべてを開始します。そのため、psgrepがすでに実行されているのを確認できます。

3
BowlOfRed

この思考実験を考えてみましょう。psを呼び出す前にgrepが最後まで実行されたとしたら、シェルは次のことを行う必要があることを意味します。

  1. psを呼び出します。
  2. すべての出力をバッファリングします(他に行く場所がまだないため)。
  3. grepを呼び出します。
  4. 保存した出力をgrepstdinにフィードします。

これは無駄です。最初にgrepを呼び出して入力を待機させ、次にpsstdoutを直接grepstdinにフィードする方がメモリを効率的に使用できます。

または、極端に言えば、無限の量の出力を生成するプログラムの出力をパイピングする場合を考えてみましょう。例:

$ yes | less

シェルがyesの前にlessを実行した場合、永遠に(またはコンピュータのメモリを完全に使い果たすまで)待機したままになります。

2
jamesdlin

BowlOfRedとalexisesが述べたように確認します。これは、psgrepを再びpsにパイピングして、パイプされたプロセスがどのように実行されるかを示す視覚的表現です。最後のps x --forestは入力を無視していますが、以前にパイプ処理されたプロセスを維持しているため、表示されます。

ps -ef | grep myprocess | ps x --forest

出力の抜粋:

25056 pts/3    Ss     0:05  \_ bash
12243 pts/3    R+     0:00  |   \_ ps -ef
12244 pts/3    S+     0:00  |   \_ grep --color=auto myprocess
12245 pts/3    R+     0:00  |   \_ ps x --forest

Bashが割り込み可能なスリープ状態S(イベントが完了するのを待っている)にあることに注意してください。 sは、以下に示すように、それがセッションリーダーであることを示します。

-efオプションを使用すると、子プロセスがbash25056のプロセスIDである同じ親IDで実行されていることも確認できます。

ps x | grep myprocess | ps -ef --forest

出力の抜粋:

UID         PID   PPID   C STIME TTY          TIME  CMD
iamuser     25056 16737  0 Dec23 pts/3    00:00:05  \_ bash
iamuser     12161 25056  0 05:02 pts/3    00:00:00  |   \_ ps x
iamuser     12162 25056  0 05:02 pts/3    00:00:00  |   \_ grep myprocess
iamuser     12163 25056  0 05:02 pts/3    00:00:00  |   \_ ps -ef --forest
1
iyrin