Почему 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 as:

 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 ?

2 Solutions collect form web for “Почему pgrep не может найти скрипты, запущенные через env?”

Вопрос # 1

Почему имя скрипта не отображается при вызове через env?

Из статьи о википедии shebang :

В Unix-подобных операционных системах, когда скрипт с shebang запускается как программа, загрузчик программ анализирует остальную часть начальной строки скрипта как директиву интерпретатора; вместо этого выполняется указанная программа интерпретатора, передавая ей в качестве аргумента путь, который изначально использовался при попытке запустить скрипт.

Таким образом, это означает, что имя сценария – это то, что известно ядру как имя процесса, но затем сразу же после его запуска загрузчик затем выполняет аргумент в #! и передает остальную часть скрипта в качестве аргумента.

Однако env этого не делает. Когда он вызывается, ядро ​​знает имя скрипта, а затем выполняет env . env затем ищет $PATH ища исполняемый файл exec.

  • Как / usr / bin / env знает, какую программу использовать?

Затем он env интерпретатор. Он ничего не знает об исходном имени скрипта, только это знает ядро. На данный момент env анализирует остальную часть файла и передает его интерпретатору, который он только что вызвал.

Вопрос # 2

Pgrep просто анализирует вывод ps?

Да, вроде. Он вызывает те же библиотеки C, что и ps . Это не просто обертка вокруг 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 

Рекомендации

  • #! / usr / bin / env Интерпретатор Аргументы – переносные скрипты с аргументами для интерпретатора
  • Почему лучше использовать «#! / Usr / bin / env NAME» вместо «#! / Path / to / NAME» в качестве моего shebang?

pgrep не анализирует вывод ps , он будет просматривать /proc/<PID>/status и /proc/<PID>/cmdline для поиска соответствия для заданного шаблона. Сделайте некоторые strace:

 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 
  • ps пользовательский выход в RHEL 6.2
  • Захват полной структуры процесса / стека
  • Как перечислить все запущенные X-приложения?
  • Есть ли способ выбрать несколько условий в `ps`?
  • Как проверить, остановлен ли процесс из командной строки?
  • Извлечь параметры tomcat из вывода ps
  • Асимметричная сессия ESTABLISHED в netstat
  • Использование регулярного выражения для проверки того, работает ли процесс UNIX
  • Как ps получает исполняемый файл от процессов других пользователей?
  • Получить список процессов с логическим пересечением селекторов?
  • Перенаправить вывод с несколькими командами
  • Linux и Unix - лучшая ОС в мире.