Как получить список всех дочерних процессов, порожденных скриптом

9

Контекст:

Пользователи предоставляют мне свои собственные скрипты для запуска. Эти сценарии могут быть любого типа, такие как сценарии для запуска нескольких программ с графическим интерфейсом, внутренних служб. Я не контролирую, как пишутся сценарии. Эти сценарии могут быть блокирующего типа, т.е. выполнение ожидает завершения всех дочерних процессов (программ, запускаемых последовательно)

#exaple of blocking script
echo "START"
first_program 
second_program 
echo "DONE"

или не блокирующий тип, то есть те, которые обрабатывают дочерний процесс в фоновом режиме и выходят что-то вроде

#example of non-blocking script
echo "START"
first_program &
second_program &
echo "DONE"

Чего я пытаюсь достичь?

Предоставляемые пользователем сценарии могут быть любого из двух указанных выше типов или сочетанием обоих. Моя задача - запустить скрипт и подождать, пока все запущенные им процессы не завершатся, а затем завершить работу узла. Если это блокирующий тип, то дело простое, т.е. получите PID процесса выполнения скрипта и подождите, пока ps -ef | grep -ef PID больше не будет иметь записей. Неблокирующие скрипты доставляют мне неприятности

Есть ли способ получить список PID всех дочерних процессов, созданных при выполнении сценария? Любые указатели или подсказки будут высоко оценены

irraju
источник
Я не думаю, что это возможно после завершения родительского сценария, если вы не можете захватить PID родительского сценария. Если вы запускаете сценарии, вы можете заключить их в что-то вроде того, pid$(foo.sh; echo $!)что даст вам PID, который foo.shвы затем сможете использовать ps --ppid. Будет ли это работать?
Тердон
2
Должны ли скрипты работать под UID автора-пользователя? Если нет, можете ли вы создать фиктивного пользователя только для этой цели? Тебе даже не нужно grep, просто ps –udummy_user. Также посмотрите на группы процессов.
Скотт
Это скорее обходной путь, чем решение исходного вопроса: откройте новый сеанс bash. Вы можете перечислить все процессы, созданные из этой оболочки, используя psбез аргументов (должно быть только bashи psв начале). Начните свой сценарий там. После того, как он закончится, подождите, пока не ps | wc -lдостигнете ожидаемого значения.
Тим

Ответы:

8

Чтобы ответить на ваш вопрос напрямую, команда

jobs -p

дает вам список всех дочерних процессов.

Альтернатива № 1

Но в вашем случае может быть проще использовать команду waitбез каких-либо параметров:

first_program &
second_program &
wait

Это будет ждать, пока ВСЕ дочерние процессы не завершатся.

Альтернатива № 2

Другой альтернативой является использование $!для получения PID последней программы и, возможно, накопления в переменной, например так:

pids=""
first_program &
pids="$pids $!"
second_program &
pids="$pids $!"

и затем используйте wait с этим (это в том случае, если вы хотите подождать только часть ваших дочерних процессов):

wait $pids

Альтернатива № 3

ИЛИ, если вы хотите подождать, пока ЛЮБОЙ процесс не завершится, вы можете использовать

wait -n $pids

Информация о бонусе

Если вы хотите, чтобы сигнатура в вашем bash-скрипте также закрывала ваши дочерние процессы, вам нужно будет распространить сигнал примерно так (поместите это где-нибудь вверху, перед началом любого процесса):

trap 'kill $(jobs -p)' SIGINT SIGTERM EXIT
Влад А Ионеску
источник
1

Спасибо, ребята, за ваши ответы .. Я получил решение по stackoverflow

Вы можете использовать wait, чтобы дождаться завершения всех фоновых процессов, запущенных usercript. Поскольку wait работает только для дочерних элементов текущей оболочки, вам нужно будет использовать их сценарий вместо того, чтобы запускать его как отдельный процесс.

(источник usercript; подождите)

Подбор сценария в явной подоболочке должен достаточно близко имитировать запуск нового процесса. Если нет, вы также можете создать фоновую подоболочку, которая заставляет запускать новый процесс, а затем дождаться его завершения.

(источник usercript; ждать) и ждать

Вот ссылка на оригинальный ответ @chepner: /programming/18663196/how-to-get-list-of-all-child-process-spawned-by-a-script/18663969?noredirect = 1 # 18663969

irraju
источник
3
Я тоже думал об этом, но это решение не работает, когда пользовательский скрипт запускает нижний индекс в фоновом режиме, который затем запускает другой скрипт в фоновом режиме. waitЗатем ваша команда будет ждать детей usercript, но не своих внуков.
Тим
@Tim Просто понял, что :(
irraju