pgrep이 env를 통해 시작된 스크립트를 찾을 수 없는 이유는 무엇입니까?

pgrep이 env를 통해 시작된 스크립트를 찾을 수 없는 이유는 무엇입니까?

예를 들어:

$ 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

관련 정보