Czy jest jakaś wbudowana funkcja w Bash, która ma czekać na zakończenie procesu?
wait
Komenda pozwala tylko jeden czekać procesów potomnych, aby zakończyć. Chciałbym wiedzieć, czy istnieje sposób, aby poczekać na zakończenie jakiegokolwiek procesu przed przystąpieniem do jakiegokolwiek skryptu.
Mechaniczny sposób na to jest następujący, ale chciałbym wiedzieć, czy w Bash jest jakaś wbudowana funkcja.
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
Odpowiedzi:
Czekać na zakończenie procesu
Linux:
Darwin (wymaga, aby
$pid
mieć otwarte pliki):Z limitem czasu (sekundy)
Linux:
Darwin (wymaga, aby
$pid
mieć otwarte pliki):źródło
tail
to zrobi.tail
działa pod maską poprzez odpytywanie zkill(pid, SIG_0)
procesem (odkrytym za pomocąstrace
).+r 1
limitu czasu, osobiście szukam rozwiązania dla MacOS, które nie używa odpytywania.tail
ma liniękill (pid, 0) != 0 && errno != EPERM
.caffeinate -w $pid
.Nie ma wbudowanej. Użyj
kill -0
w pętli, aby uzyskać działające rozwiązanie:Lub jako prostszy oneliner do łatwego jednorazowego użycia:
Jak zauważyło kilku komentatorów, jeśli chcesz czekać na procesy, do których nie masz uprawnień do wysyłania sygnałów, musisz znaleźć inny sposób na wykrycie, czy proces jest uruchomiony, aby zastąpić
kill -0 $pid
wywołanie. W systemie Linuxtest -d "/proc/$pid"
działa, w innych systemach może być konieczne użyciepgrep
(jeśli jest dostępny) lub czegoś podobnegops | grep "^$pid "
.źródło
sleep 0.5
proces$pid
może umrzeć, a inny proces może zostać utworzony z tym samym$pid
. I skończymy czekać na 2 różne procesy (lub nawet więcej) z tym samym$pid
.Zauważyłem, że "kill -0" nie działa, jeśli właścicielem procesu jest root (lub inny), więc użyłem pgrep i wymyśliłem:
Miałoby to tę wadę, że prawdopodobnie pasowałoby do procesów zombie.
źródło
kill(pid, sig=0)
kończy się niepowodzeniem, jeśli proces wywołujący nie ma uprawnień do zabicia. Zatem / bin / kill -0 i "kill -0" (wbudowany bash) również zawodzą w tych samych warunkach.Ta pętla skryptu bash kończy się, jeśli proces nie istnieje lub jest zombie.
EDYCJA : Powyższy skrypt został podany poniżej przez Rockallite . Dzięki!
Moja oryginalna odpowiedź poniżej działa dla systemu Linux, polegając na
procfs
np/proc/
. Nie znam jego przenośności:Nie ogranicza się to do powłoki, ale same systemy operacyjne nie mają wywołań systemowych do obserwowania zakończenia procesu innego niż dziecko.
źródło
grep /proc/$PID/status
się podwójnymi cudzysłowami (bash: test: argument expected
)while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do sleep 1; done
ps
, ani-p
czys=
są obsługiwaneFreeBSD i Solaris mają to przydatne
pwait(1)
narzędzie, które robi dokładnie to, co chcesz.Uważam, że inne nowoczesne systemy operacyjne również mają niezbędne wywołania systemowe (na przykład MacOS implementuje BSD
kqueue
), ale nie wszystkie udostępniają je z wiersza poleceń.źródło
> BSD and Solaris
: Sprawdzanie trzech dużych BSD, które przychodzą mi do głowy; ani OpenBSD, ani NetBSD nie mają tej funkcji (na swoich stronach podręcznika ), tylko FreeBSD ma, co można łatwo sprawdzić na man.openbsd.org .kqueue
, więc kompilacja FreeBSDpwait(1)
byłaby jednak trywialna. Dlaczego inny BSD nie importowałby tej funkcji, ucieka mi ...plink me@oracle box -pw redacted "pwait 6998";email -b -s "It's done" etc
po prostu pozwolił mi wrócić do domu teraz zamiast za kilka godzin.Ze strony podręcznika bash
źródło
wait
bez argumentów blokuje proces do zakończenia procesu potomnego . Szczerze mówiąc, nie widzę sensu czekać na jakikolwiek proces, ponieważ zawsze trwają procesy systemowe.sleep 1000
ctrl-z
wait [sleep pid]
wraca natychmiastWszystkie te rozwiązania są testowane w Ubuntu 14.04:
Rozwiązanie 1 (za pomocą polecenia ps): Aby dodać do odpowiedzi Pierz, proponuję:
W tym przypadku
grep -vw grep
zapewnia, że grep pasuje tylko do procesu nazwa_procesu, a nie do samego grep. Ma tę zaletę, że obsługuje przypadki, w których nazwa_procesu nie znajduje się na końcu wiersza wps axg
.Rozwiązanie 2 (używając najwyższego polecenia i nazwy procesu):
Zastąp
process_name
nazwę procesu, która pojawia się wtop -n 1 -b
. Proszę zachować cudzysłowy.Aby zobaczyć listę procesów, które czekasz na zakończenie, możesz uruchomić:
Rozwiązanie 3 (przy użyciu polecenia górnego i identyfikatora procesu):
Zastąp
process_id
identyfikatorem procesu swojego programu.źródło
grep -v grep
potok jest ogromnym antywzorem, a to zakłada, że nie masz niepowiązanych procesów o tej samej nazwie. Jeśli zamiast tego znasz PID, można to dostosować do poprawnie działającego rozwiązania.-w
aby wgrep -v grep
pewnym stopniu uniknąć problemu . Dodałem również dwa kolejne rozwiązania na podstawie twojego komentarza.Okay, więc wydaje się, że odpowiedź brzmi - nie, nie ma wbudowanego narzędzia.
Po ustawieniu
/proc/sys/kernel/yama/ptrace_scope
się0
, możliwe jest korzystanie zstrace
programu. Można użyć dalszych przełączników, aby wyciszyć go, aby naprawdę czekał pasywnie:źródło
Operation not permitted
dla drugiej instancji strace); czy możesz to potwierdzić?(...)"tracee" always means "(one) thread"
(i potwierdzam błąd, o którym wspomniałeś). Aby więcej procesów czekało w ten sposób, musiałbyś utworzyć łańcuch.Rozwiązanie blokujące
Użyj
wait
pętli w celu oczekiwania na zakończenie wszystkich procesów:Ta funkcja kończy się natychmiast po zakończeniu wszystkich procesów. To najbardziej wydajne rozwiązanie.
Rozwiązanie nieblokujące
Użyj
kill -0
pętli w celu oczekiwania na zakończenie wszystkich procesów + rób cokolwiek między sprawdzeniami:Czas reakcji skrócił się do
sleep
czasu, ponieważ trzeba zapobiegać wysokiemu zużyciu procesora.Realistyczne użycie:
Oczekiwanie na zakończenie wszystkich procesów + poinformowanie użytkownika o wszystkich działających PIDach.
Uwagi
Te funkcje pobierają PIDy za pośrednictwem argumentów
$@
jako tablica BASH.źródło
Gdy miałem ten sam problem, rozwiązałem go, zabijając proces, a następnie czekając na zakończenie każdego procesu przy użyciu systemu plików PROC:
źródło
Nie ma wbudowanej funkcji czekającej na zakończenie jakiegokolwiek procesu.
Możesz wysłać
kill -0
do dowolnego znalezionego PID, więc nie zdziwisz się zombie i rzeczy, które będą nadal widoczne wps
(podczas wciąż pobierania listy PID za pomocąps
).źródło
Użyj inotifywait, aby monitorować jakiś plik, który zostaje zamknięty po zakończeniu procesu. Przykład (w systemie Linux):
-e określa zdarzenie, na które należy czekać, -q oznacza minimalne wyjście tylko po zakończeniu. W tym przypadku będzie to:
Do oczekiwania na wiele procesów można użyć jednego polecenia oczekiwania:
Wynikowy ciąg inotifywait powie ci, który proces został zakończony. Działa to tylko z „prawdziwymi” plikami, a nie z czymś w / proc /
źródło
W systemie takim jak OSX możesz nie mieć pgrep, więc możesz wypróbować tę metodę, szukając procesów według nazwy:
$
Symbol na końcu nazwy, zapewnia, że proces grep mecze process_name tylko do końca linii w wyjściu ps a nie sama.źródło
/dev/null
,-q
należy używać zgrep
. Inny przypadek procesu mógł się rozpocząć, gdy twoja pętla spała i nigdy się nie dowiesz ...-q
sugestia jest słuszna, jak wspomniałem w mojej odpowiedzi konkretnie, terminacja$
oznacza, że grep nie będzie pasował do nazwy „gdzieś w linii poleceń” ani nie będzie pasować do siebie. Czy rzeczywiście próbowałeś tego na OSX?Rozwiązanie Rauno Palosaari dla
Timeout in Seconds
Darwin
, jest doskonałym obejściem dla systemu operacyjnego podobnego do UNIX, który nie ma GNUtail
(nie jest specyficzny dlaDarwin
). Jednak w zależności od wieku systemu operacyjnego podobnego do UNIX, oferowany wiersz poleceń jest bardziej złożony niż to konieczne i może zawieść:Na co najmniej jednym starym UNIXie
lsof
argument+r 1m%s
zawodzi (nawet dla superużytkownika):m%s
Jest specyfikacja formatu wyjściowego. Prostszy postprocesor tego nie wymaga. Na przykład następujące polecenie czeka na PID 5959 przez maksymalnie pięć sekund:W tym przykładzie, jeśli PID 5959 kończy się samoistnie przed upływem pięciu sekund,
${?}
to jest0
. Jeśli nie${?}
wraca1
po pięciu sekundach.Warto wyraźnie zauważyć, że w
+r 1
programie1
jest interwał odpytywania (w sekundach), więc można go zmienić w zależności od sytuacji.źródło