pgrep -P $$ дает несуществующий идентификатор процесса

#!/usr/bin/env bash
sleep 3 &                               # Spawn a child

trap '
    pgrep -P $$                         # Outputs one PID as expected
    PIDS=( $( pgrep -P $$ ) )           # Saves an extra nonexistant PID
    echo "PIDS: ${PIDS[@]}"             # You can see it is the last one
    ps -o pid= "${PIDS[@]:(-1)}" ||
    echo "Dafuq is ${PIDS[@]:(-1)}?"    # Yep, it does not exist!

' 0 1 2 3 15

Он выводит

11800
PIDS: 11800 11802
Dafuq is 11802?

Это происходит только с ловушками. Почему к массиву добавляется несуществующий PID? И как избежать этого странного поведения?


person Dude    schedule 26.04.2015    source источник


Ответы (1)


Используя $(...), вы создали подпроцесс, который будет выполнять этот код.

Естественно, родителем этого процесса будет текущая оболочка, поэтому она будет указана в списке.

Что касается обходного пути, вы можете удалить этот PID из списка. Сначала вам нужно знать, как получить доступ к PID подоболочки: $$ в сценарии против $$ в подоболочке . Теперь вы можете это отфильтровать (нет, это не работает):

PIDS=( $( pgrep -P $$ | grep -v ^$BASHPID$ ) )
person Karoly Horvath    schedule 26.04.2015
comment
Дело в том, что странное поведение исчезает, если ловушки нет. - person Dude; 26.04.2015
comment
Вероятно, это связано с тем, как trap реализован в bash.. но я не в настроении копаться в исходном коде, это точно.. :D - person Karoly Horvath; 26.04.2015
comment
Я думаю, да, но как избежать меня все еще беспокоит. - person Dude; 26.04.2015
comment
это похожая проблема, которая часто возникает: serverfault.com/questions/367921/ разве вы не тестировали то, что я предложил? - person Karoly Horvath; 26.04.2015
comment
Спасибо Кароли, первый был полезен. Так что да, $( pgrep -P $$ ) порождает странный процесс. РЕДАКТИРОВАТЬ: Извините, я опечатался, но в любом случае я все еще ошибался. Таким образом, обходным путем было бы вручную удалить этот идентификатор процесса подоболочки, есть ли лучший способ? - person Dude; 26.04.2015
comment
О, $BASHPID изменяется после канала, поэтому grep -v не будет его фильтровать echo $BASHPID $( echo $BASHPID; echo $BASHPID; true | echo $BASHPID ) выводит 11623 13404 13404 13406 - person Dude; 26.04.2015
comment
черт возьми, вы правы... не знаю, сделайте запрос дважды, оставьте только те идентификаторы, которые появляются в обоих :) Но вы действительно должны использовать $! и избегать pgrep... - person Karoly Horvath; 27.04.2015