たとえば、
$ cat foo.sh
#!/usr/bin/env bash
while true; do sleep 1 ; done
$ ./foo.sh &
$ pgrep foo.sh
$
比較:
$ cat bar.sh
#!/bin/bash
while true; do sleep 1 ; done
$ ./bar.sh &
$ pgrep bar.sh
21202
次のコマンドで開始されたプロセスが出力env bash
に表示されますps aux
。
terdon 4203 0.0 0.0 26676 6340 pts/3 S 17:23 0:00 /bin/bash
/bin/bash
ディスプレイの始まり
terdon 9374 0.0 0.0 12828 1392 pts/3 S 17:27 0:00 /bin/bash ./bar.sh
これがおそらく当初はキャプチャされていない理由を説明しているようですpgrep
。したがって、質問は次のようになります。
- 呼び出し時にスクリプト名が表示されないのはなぜですか
env
? pgrep
出力は単に解析されますかps
?pgrep
実行中のスクリプトを表示できるようにこの問題を解決する方法はありますかenv
?
答え1
質問1
envを介して呼び出すときにスクリプト名が表示されないのはなぜですか?
~から体本ウィキペディア記事:
Unixファミリーのオペレーティングシステムでは、shebangを持つスクリプトがプログラムとして実行されると、プログラムローダはスクリプトの最初の行の残りの部分をインタプリタコマンドで解析し、代わりに指定されたインタプリタを実行してスクリプトを実行しようとします。最初に使用されたパスはパラメータとして渡されます。
したがって、これが意味するのは、スクリプトの名前がカーネルに知られているプロセス名ですが、それを呼び出した直後にローダーが引数を実行し、残りのスクリプトを引数として渡すということ#!
です。
しかし、env
そうしないでください。呼び出されると、カーネルはスクリプト名を知ってそれを実行しますenv
。env
次に、$PATH
実行する実行可能ファイルを検索します。
次にenv
インタプリタを実行します。スクリプトの元の名前は知らず、カーネルだけを知っています。この時点で、env
ファイルの残りの部分が解析され、呼び出されたばかりのインタプリタに渡されます。
質問#2
pgrepは単にpsの出力を解析しますか?
はい、そうです。ps
使用しているのと同じCライブラリを呼び出します。これは単なる包装紙以上ですps
。
質問#3
pgrepがenvを介して起動されたスクリプトを表示できるように、この問題を解決する方法はありますか?
出力に実行可能ファイルの名前を表示できますps
。
$ ps -eaf|grep 32405
saml 32405 24272 0 13:11 pts/27 00:00:00 bash ./foo.sh
saml 32440 32405 0 13:11 pts/27 00:00:00 sleep 1
この場合、pgrep -f <name>
実行可能ファイルだけでなくコマンドライン引数全体を検索するので、それを使用して実行可能ファイルを見つけることができます。
$ pgrep -f foo
32405
引用する
答え2
pgrep
出力を解析せずに、指定されたパターンに一致する項目をps
検索し/proc/<PID>/status
て検索します。/proc/<PID>/cmdline
トレースを実行します。
getpid() = 6572
stat("/proc/self/task", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
getdents(3, /* 267 entries */, 32768) = 6792
stat("/proc/1", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/1/status", O_RDONLY) = 4
read(4, "Name:\tinit\nState:\tS (sleeping)\nT"..., 1023) = 750
close(4) = 0
open("/proc/1/cmdline", O_RDONLY) = 4
read(4, "/sbin/init", 2047) = 10
close(4) = 0
stat("/proc/2", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/2/status", O_RDONLY) = 4
read(4, "Name:\tkthreadd\nState:\tS (sleepin"..., 1023) = 518
close(4) = 0
open("/proc/2/cmdline", O_RDONLY) = 4
read(4, "", 2047) = 0
close(4) = 0
stat("/proc/3", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/3/status", O_RDONLY) = 4
read(4, "Name:\tksoftirqd/0\nState:\tS (slee"..., 1023) = 521
close(4) = 0
open("/proc/3/cmdline", O_RDONLY) = 4
read(4, "", 2047) = 0
close(4) = 0
stat("/proc/6", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
open("/proc/6/status", O_RDONLY) = 4
read(4, "Name:\tmigration/0\nState:\tS (slee"..., 1023) = 519
close(4) = 0
open("/proc/6/cmdline", O_RDONLY) = 4
read(4, "", 2047) = 0
close(4) = 0
デフォルトでは、pgrep
プロセス名のみが一致します(あなたの場合はbash)。からman pgrep
:
-f The pattern is normally only matched against the process name.
When -f is set, the full command line is used.
したがって、あなたのケースで開始されたスクリプトを表示するには、env
次を試してください。
pgrep -f foo.sh