pgrep {process_name} | w c -l возвращает неверные результаты - PullRequest
0 голосов
/ 06 мая 2020

У меня есть этот скрипт (test. sh):

#!/bin/bash

echo "pgreg --- start"
pgrep 'test.sh'
echo "pgrep --- end"

process_count=`pgrep 'test.sh' | wc -l`
echo "process_count = $process_count"

pids=`pgrep 'test.sh'`;
fixed_count_process=`echo $pids | wc -w`
echo "pids = $pids";
echo "fixed_count_process = $fixed_count_process"

Результат этого скрипта всегда:

pgreg --- start
56516
pgrep --- end
process_count = 2
pids = 56516
fixed_count_process = 1

Я не могу найти логического объяснения, почему сохранение вывода pgrep в переменной перед его передачей в wc дает правильные результаты. Любая помощь?

Заранее спасибо!

1 Ответ

1 голос
/ 06 мая 2020

Итак, сначала делаем ./test.sh с терминала. Итак, у нас есть один процесс с именем test.sh.

process_count=`pgrep 'test.sh' | wc -l`

Подстановка команд, вызываемая обратными кавычками, запускает подоболочку. Подоболочка - это отдельный процесс с тем же именем test.sh. Итак, теперь есть два процесса с разными pid, которые имеют имя test.sh. Таким образом, pgrep возвращает две строки.

Это можно, например, проверить с помощью:

process_count=$(
        ps -e -o pid,comm | grep 'test.sh' >&2
        echo BASHPID=$BASHPID \$=$$ >&2
        pgrep 'test.sh' | wc -l
)

с выходами на stderr:

 495463 test.sh
 495466 test.sh
BASHPID=495466 $=495463

495466 is pid подоболочки, а 495463 - pid процесса родительской оболочки.

Когда вы это делаете:

pids=`pgrep 'test.sh'`;

это выводит единственный pid. Это связано с тем, что bash имеет оптимизацию, которая при определенных c обстоятельствах (например, no trap s), когда только один процесс остается для выполнения в оболочке, он оптимизируется и не вызывает fork()+exec() вместо этого вызывает просто exec, потому что следующего процесса не будет, поэтому он может просто выйти. Внутренняя подоболочка с именем процесса test.sh существует только в течение короткого времени, подоболочка обнаруживает, что есть только одна команда для запуска, поэтому она пропускает fork(), просто выполняет exec("pgrep") и становится процессом с именем процесса pgrep. Вот почему в этом случае вы не видите другой pid.

Примечания: Пожалуйста, не используйте обратные кавычки `. Вместо этого используйте $(...).

Дополнительно: больше подоболочек! Следующие

echo "$(echo "$(echo "$(pgrep 'test.sh' | wc -l)")")"
# would output 4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...