Mam prosty skrypt bash, który uruchamia dwa serwery:
#!/bin/bash
(cd ./frontend && gulp serve) & (cd ./backend && gulp serve --verbose)
Jeśli drugie polecenie zakończy działanie, wydaje się, że pierwsze polecenie nadal działa.
Jak mogę to zmienić, aby jedno z poleceń zakończyło się, a drugie zostanie zakończone?
Pamiętaj, że nie musimy sprawdzać poziomów błędów procesów w tle, tylko czy zakończyły się.
bash
shell-script
background-process
blah238
źródło
źródło
gulp ./fronend/serve && gulp ./backend/serve --verbose
?serve
jest argumentem, a nie plikiem, dlatego należy ustawić bieżący katalog.Odpowiedzi:
To uruchamia oba procesy, czeka na pierwszy, który się kończy, a następnie zabija drugi:
Jak to działa
Początek:
Powyższe dwa polecenia uruchamiają oba procesy w tle.
Czekać
To czeka na zakończenie zadania w tle.
Z powodu tej
-n
opcji wymaga to wersji bash 4.3 lub nowszej.Zabić
To zabija każde zadanie, dla którego bieżący proces jest nadrzędny. Innymi słowy, zabija to cały działający proces w tle.
Jeśli twój system nie ma
pkill
, spróbuj zastąpić ten wiersz:co również zabija bieżącą grupę procesów .
Łatwo testowalny przykład
Zmieniając skrypt, możemy go przetestować nawet bez
gulp
instalacji:Powyższy skrypt można uruchomić jako,
bash script.sh 1 3
a pierwszy proces kończy się jako pierwszy. Alternatywnie można uruchomić go jako,bash script.sh 3 1
a drugi proces zakończy się jako pierwszy. W obu przypadkach widać, że działa to zgodnie z potrzebami.źródło
bash
obsługują-n
opcjęwait
polecenia. (2) Zgadzam się w 100% z pierwszym zdaniem - twoje rozwiązanie rozpoczyna dwa procesy, czeka na zakończenie pierwszego, a następnie zabija drugie. Ale pytanie brzmi „… jeśli jedno z poleceń się nie powiedzie , drugie zostanie zakończone?” Uważam, że twoje rozwiązanie nie jest tym, czego chce PO. (3) Dlaczego zmieniłeś się(…) &
na{ …; } &
? Te&
siły lista (komenda grupa), aby uruchomić w podpowłoce tak. IMHO, dodałeś postacie i prawdopodobnie wprowadziłeś zamieszanie (musiałem na to spojrzeć dwa razy, aby to zrozumieć) bez żadnej korzyści.pkill
nie jest dla mnie dostępny, alekill 0
wydaje się mieć ten sam efekt. Zaktualizowałem także środowisko Git dla Windows i wygląda na to, żewait -n
teraz działa, więc akceptuję tę odpowiedź.kill
. dokumentacja mojego systemu nie wspomina o tym. Jednak ikill 0
tak działa. Dobre znalezisko!To trudne. Oto, co wymyśliłem; możliwe jest uproszczenie / usprawnienie:
while true; do sleep 42; done &
), który śpi / zatrzymuje się na zawsze. Jeśli masz pewność, że twoje dwa polecenia zakończą się w określonym czasie (np. Godzinie), możesz zmienić to na pojedynczy sen, który go przekroczy (npsleep 3600
.). Następnie możesz zmienić następującą logikę, aby użyć tego jako limitu czasu; tzn. zabij procesy, jeśli nadal działają po tak długim czasie. (Uwaga: powyższy skrypt obecnie tego nie robi)../
zacd
.command & echo "$!" > somewhere; wait "$!"
jest trudną konstrukcją, która uruchamia proces asynchronicznie, przechwytuje swój PID, a następnie czeka na niego; dzięki czemu jest to rodzaj procesu pierwszego planu (synchronicznego). Ale dzieje się tak na(…)
liście, która jest w całości w tle, więcgulp
procesy przebiegają asynchronicznie.gulp
procesów zapisz jego status do pliku tymczasowego i zabij proces „na zawsze”.sleep 1
aby zabezpieczyć się przed wyścigiem, w którym pierwszy proces w tle umiera, zanim drugi ma szansę zapisać swój PID w pliku.gulp
procesów, jak wspomniano powyżej.źródło
Dla kompletności oto, co skończyło się na użyciu:
Działa to dla mnie na Git dla Windows 2.5.3 64-bit. Starsze wersje mogą nie akceptować tej
-n
opcjiwait
.źródło
W moim systemie (Centos),
wait
nie mam,-n
więc zrobiłem to:To nie czeka na „jedno”, a raczej czeka na pierwsze. Ale nadal może pomóc, jeśli wiesz, który serwer zostanie zatrzymany jako pierwszy.
źródło
wait
ma taką-n
opcję, zależy od używanej powłoki, a nie od dystrybucji Linuksa.