私がいくつかのプロセスをチェックしているとき、私は通常書く
ps aux | grep myprocess
そして時々の出力を取得します
eimantas 11998 0.0 0.0 8816 740 pts/0 S+ 07:45 0:00 grep myprocess
プロセスが実行されていない場合。
ps
コマンドの出力を除外すると、なぜgrepがプロセスのリストに含まれるのか、本当に疑問に思いますafterps
が実行されましたか?
この動作は完全に正常です。これは、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
プロセスの存在のみに関心がある場合は、この動作を示さないpgrep
を使用します。例:
$ pgrep myprocess
1900
その他の場合(詳細に興味がある場合)、通常は| grep -v grep
を追加して、grep行を破棄します。例:
$ ps -ef | grep myprocess| grep -v grep
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 ~]$
あなたは正しいです、それはそれがどのように機能するかではありません。シェルは、パイプラインの最初のプロセスが終了するのを待たずに、次のプロセスを開始します。それはそれらすべてを開始します。そのため、ps
はgrep
がすでに実行されているのを確認できます。
この思考実験を考えてみましょう。ps
を呼び出す前にgrep
が最後まで実行されたとしたら、シェルは次のことを行う必要があることを意味します。
ps
を呼び出します。grep
を呼び出します。grep
のstdin
にフィードします。これは無駄です。最初にgrep
を呼び出して入力を待機させ、次にps
のstdout
を直接grep
のstdin
にフィードする方がメモリを効率的に使用できます。
または、極端に言えば、無限の量の出力を生成するプログラムの出力をパイピングする場合を考えてみましょう。例:
$ yes | less
シェルがyes
の前にless
を実行した場合、永遠に(またはコンピュータのメモリを完全に使い果たすまで)待機したままになります。
BowlOfRedとalexisesが述べたように確認します。これは、ps
とgrep
を再び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
オプションを使用すると、子プロセスがbash
、25056
のプロセス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