Jak uzyskać listę wszystkich procesów potomnych odradzanych przez skrypt

10

Kontekst:

Użytkownicy udostępniają mi swoje niestandardowe skrypty do uruchomienia. Skrypty te mogą być wszelkiego rodzaju jak skrypty do uruchamiania wielu programów GUI, usług zaplecza. Nie mam kontroli nad sposobem pisania skryptów. Skrypty te mogą być typu blokującego, tzn. Wykonywanie czeka do momentu zakończenia wszystkich procesów potomnych (programów uruchamianych sekwencyjnie)

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

lub typu nieblokującego, tzn. takie, które rozwidlają proces potomny w tle i zamykają coś podobnego

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

Co próbuję osiągnąć?

Skrypty dostarczone przez użytkownika mogą należeć do dowolnego z powyższych dwóch typów lub być kombinacją obu. Moim zadaniem jest uruchomienie skryptu i poczekanie, aż wszystkie procesy rozpoczęte przez niego zakończą się, a następnie zamkną węzeł. Jeśli jest typu blokującego, wielkość liter jest po prostu prosta, tzn. Uzyskaj PID procesu wykonywania skryptu i poczekaj, aż ps -ef | grep -ef PID nie będzie już zawierał żadnych wpisów. Skrypty nieblokujące powodują problemy

Czy istnieje sposób, aby uzyskać listę PID wszystkich procesów potomnych odradzanych przez wykonanie skryptu? Wszelkie wskazówki lub wskazówki będą mile widziane

irraju
źródło
Nie sądzę, że jest to możliwe po zakończeniu skryptu nadrzędnego, chyba że można przechwycić PID rodzica. Jeśli uruchamiasz skrypty, możesz zawinąć je w coś, pid$(foo.sh; echo $!)co da ci PID foo.sh, abyś mógł z niego skorzystać ps --ppid. Czy to będzie działało?
terdon
2
Czy skrypty muszą być uruchamiane z identyfikatorem UID użytkownika-autora? Jeśli nie, czy możesz stworzyć fikcyjnego użytkownika tylko w tym celu? Ty nawet nie trzeba grep, po prostu ps –udummy_user. Zobacz także grupy procesów.
Scott
Jest to raczej rodzaj obejścia niż rozwiązanie pierwszego pytania: Otwórz nową sesję bash. Możesz wyświetlić listę wszystkich procesów spawnowanych z tej powłoki przy użyciu psbez żadnych argumentów (powinno być tylko bashi psna początku). Rozpocznij swój skrypt tam. Po zakończeniu poczekaj, aż ps | wc -losiągnie oczekiwaną wartość.
Tim

Odpowiedzi:

8

Aby bezpośrednio odpowiedzieć na twoje pytanie, polecenie

jobs -p

daje listę wszystkich procesów potomnych.

Alternatywa nr 1

Ale w twoim przypadku może być łatwiej po prostu użyć polecenia waitbez żadnych parametrów:

first_program &
second_program &
wait

Będzie to czekało na zakończenie WSZYSTKICH procesów potomnych.

Alternatywa # 2

Inną alternatywą jest użycie, $!aby uzyskać PID ostatniego programu i być może skumulować w zmiennej, tak jak:

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

a następnie użyj z tym czekania (w przypadku, gdy chcesz tylko czekać na podzbiór procesów potomnych):

wait $pids

Alternatywa nr 3

LUB, jeśli chcesz czekać tylko na zakończenie ŻADNEGO procesu, możesz użyć

wait -n $pids

Informacje o bonusie

Jeśli chcesz, aby sigterm w skrypcie bash również zamykał procesy potomne, musisz propagować sygnał za pomocą czegoś takiego (umieść to gdzieś u góry, przed rozpoczęciem jakiegokolwiek procesu):

trap 'kill $(jobs -p)' SIGINT SIGTERM EXIT
Vlad A Ionescu
źródło
1

Dzięki chłopaki za odpowiedzi. Mam rozwiązanie w sprawie stackoverflow

Możesz użyć funkcji wait, aby poczekać na zakończenie wszystkich procesów uruchomionych przez skrypt użytkownika w tle. Ponieważ czekanie działa tylko na elementach potomnych bieżącej powłoki, będziesz musiał pobrać ich skrypt zamiast uruchamiać go jako osobny proces.

(źródłowy skrypt użytkownika; czekaj)

Pozyskanie skryptu w jawnej podpowłoce powinno wystarczająco dokładnie symulować rozpoczęcie nowego procesu. Jeśli nie, możesz także utworzyć podkładkę w tle, co wymusza uruchomienie nowego procesu, a następnie poczekaj na jego zakończenie.

(źródłowy skrypt użytkownika; czekaj) i czekaj

Oto link do oryginalnej odpowiedzi @chepner: /programming/18663196/how-to-get-list-of-all-child-process-spawned-by-a-script/18663969?noredirect = 1 # 18663969

irraju
źródło
3
Myślałem również o tym, ale to rozwiązanie zawiedzie, gdy skrypt użytkownika uruchamia indeks dolny w tle, a następnie uruchamia inny skrypt w tle. Twoje waitpolecenie będzie wtedy czekać na dzieci skryptu użytkownika, ale nie na jego wnuki.
Tim
@ Tim Właśnie zdał sobie sprawę, że :(
irraju