pgrep возвращает дополнительные процессы при передаче другими командами

Вот очень странный вопрос об использовании pgrep для поиска, какие процессы оболочки выполняют тот же сценарий, что и текущий.

Вот тестовый скрипт с именем test.sh

      #!/bin/bash

full_res=`pgrep -a -l -f 'test\.sh'`

res=$(pgrep -a -l -f 'test\.sh' | cat)

echo "short result is $full_res"

echo "weird result is $res"

При выходе

      sh test.sh &
[1] 19992
➜  logs short result is 19992 sh test.sh
weird result is 19992 sh test.sh
19996 sh test.sh

[1]  + 19992 done       sh test.sh

Я не знаю, где19996 sh test.shисходит, особенно при использовании трубы для кошки. Я считаю, что это может быть ошибка в реализации pgrep.

Жду разумного объяснения

Спасибо,

Балин

2 ответа

Когда вы создали конвейер с помощью обратных кавычек или$(...)создается подоболочка, которая является точной копией исходной оболочки bash, которую вы вызвали.

В тот момент, когда вы выполняете pgrep, на самом деле у вас есть следующее:

      bash test.sh
  └─bash test.sh
      └─ pgrep -f test.sh
      └─ cat

Такpgrepделает то, что вы просили.

Вы можете смоделировать это поведение следующим образом.

      #!/bin/bash
echo mypid $$
$(sleep 60 | sleep 60 | sleep 60)

Запустите процесс в фоновом режиме, используя выданный им pid, проверьте его с помощьюpstree.

      $ ./test.bash 
mypid 335153
^Z
[1]+  Stopped                 ./test.bash
$ bg
[1]+ ./test.bash &
$ pstree -p 335153
test.bash(335153)───test.bash(335154)─┬─sleep(335155)
                                      ├─sleep(335156)
                                      └─sleep(335157)

Из Pipelines в руководстве по bash:

Каждая команда в многокомандном конвейере, в котором создаются каналы, выполняется в своей подоболочке, представляющей собой отдельный процесс.

Кстати, вот почему это не сработает:

      date | read theDate
echo "$theDate"

посколькуreadкоманда выполняется в подоболочке, поэтомуtheDateпеременная заполняется в подоболочке, а не в текущей оболочке.

Другие вопросы по тегам