Заставить команду ожидания Linux ждать ВСЕ дочерние процессы

Ожидание не означает остановку всех дочерних процессов. Это мой сценарий:

#!/bin/bash

titlename=`echo "$@"|sed 's/\..\{3\}$//'`
screen -X title "$titlename"

/usr/lib/process.bash -verbose $@

wait

bash -c "mail.bash $@"
screen -X title "$titlename.Done"

У меня нет доступа к /usr/lib/process.bash, но это скрипт, который часто меняется, поэтому я хотел бы сослаться на него... но в этом скрипте:

#!/bin/ksh
#lots of random stuff
/usr/lib/runall $path $auto $params > /dev/null 2>&1&

Моя проблема в том, что runall создает файл журнала... и mail.bash должен отправить мне этот файл журнала, но ожидание не ждет runall для завершения, похоже, он ждет только завершения process.bash. В любом случае, без доступа к process.bash или попытки поддерживать мою собственную версию process.bash в актуальном состоянии, чтобы заставить ожидание правильно ждать runall закончить? (лог-файл перезаписывает предыдущий запуск, поэтому я не могу просто проверить наличие лог-файла, так как он там всегда есть)

Спасибо, Дэн


person Dan    schedule 18.02.2010    source источник
comment
Можете ли вы предоставить нам соответствующие части ps -ef после завершения wait? Это должно показать, какие процессы запущены и какой процесс является дочерним по отношению к другому процессу...   -  person Heinzi    schedule 18.02.2010
comment
Мой скрипт и Process.bash заканчиваются почти мгновенно. Единственный оставшийся процесс — это runall, который запускается со случайным PID.   -  person Dan    schedule 18.02.2010


Ответы (4)


(
    . /usr/lib/process.bash -verbose $@
    wait
)

Вместо того, чтобы позволить ОС запустить process.bash, это создает подоболочку, запускает все команды в process.bash, как если бы они были введены в наш сценарий оболочки, и ожидает внутри этой подоболочки.

Есть несколько предостережений, но это должно сработать, если вы не делаете ничего необычного.

person ephemient    schedule 18.02.2010
comment
Вау... так тогда runall потому что это дочерний процесс моего скрипта? Это сработало как шарм (мне пришлось изменить свой скрипт на ksh, чтобы он соответствовал process.bash). Ctrl+C только останавливает ожидание вместо runall... В идеале я мог бы просто запустить process.bash только без &, но я не могу изменить этот код и не хочу обновлять свой код каждый раз, когда процесс .bash изменяется. Спасибо. - person Dan; 18.02.2010
comment
Чтобы Ctrl-C убил фоновый процесс, используйте trap and kill: pid=$!; trap "kill $pid; wait $pid; exit 0" SIGINT SIGTERM; wait $pid - person John Kugelman; 18.02.2010

wait ждет только прямых потомков; если какие-то дети порождают своих собственных детей, он не будет ждать их.

person Ignacio Vazquez-Abrams    schedule 18.02.2010
comment
Есть ли что-нибудь вокруг этого? Если я хочу, чтобы он ждал всех детей, прямых и косвенных? - person Dan; 18.02.2010
comment
Единственный другой способ — ждать по PID или по спецификации задания. - person Ignacio Vazquez-Abrams; 18.02.2010

Основная проблема заключается в том, что поскольку process.bash завершил работу, процесс runall станет осиротевшим и будет принадлежать init (PID 1). Если вы посмотрите на список процессов, runall больше не будет иметь никакой видимой связи с вашим процессом, так как промежуточный сценарий process.bash завершился. Невозможно использовать ps --ppid или что-то подобное для поиска этого «внучатого» процесса, когда он осиротел.

Вы можете wait использовать определенный PID. Вы знаете PID процесса runall? Если есть только один такой процесс, вы можете попробовать это, который будет ждать всех запущенных runalls:

wait `pidof runall`
person John Kugelman    schedule 18.02.2010
comment
Это не работает, поскольку runall не является дочерним элементом исходного сценария. - person abhaga; 10.03.2011

Вы можете восстановить PID процесса, которого вы хотите дождаться

А затем передать этот PID в качестве аргумента команде Wait

person Debugger    schedule 19.02.2010