Zaczynam proces w tle od skryptu powłoki i chciałbym go zabić po zakończeniu skryptu.
Jak uzyskać PID tego procesu ze skryptu powłoki? O ile widzę zmienna $!
zawiera PID bieżącego skryptu, a nie proces w tle.
linux
shell
background-process
pid
Włodzimierz Bezugły
źródło
źródło
Odpowiedzi:
Musisz zapisać PID procesu w tle podczas jego uruchamiania:
Nie można używać kontroli zadań, ponieważ jest to funkcja interaktywna i powiązana z terminalem sterującym. Do skryptu niekoniecznie musi być podłączony terminal, więc kontrola zadań niekoniecznie będzie dostępna.
źródło
foo
i$!
, i otrzymujemy, że coś jest pid zamiast zamiastfoo
?foo
zdarzy się wiele poleceń potokowych (np.tail -f somefile.txt | grep sometext
). W takich przypadkach otrzymasz PID polecenia grep$!
zamiast polecenia tail, jeśli tego właśnie szukałeś. W tym przypadku będziesz musiał użyćjobs
lubps
lubić.grep
, ale jeśli go zabijesz, ogon dostanie SIGPIPE, gdy spróbuje napisać na rurze. Ale gdy tylko spróbujesz dostać się do jakiegokolwiek trudnego zarządzania / kontroli procesu, bash / shell staje się dość bolesny./bin/sh -c 'echo $$>/tmp/my.pid && exec program args' &
- dysfunkcja 24 listopada 10 o 14:28Możesz użyć
jobs -l
polecenia, aby dostać się do określonego zadaniaLW tym przypadku 46841 jest PID.
Od
help jobs
:jobs -p
to kolejna opcja, która pokazuje tylko PID.źródło
$!
razu po uruchomieniu jest bardziej przenośne i prostsze w większości sytuacji. Tak właśnie działa obecnie akceptowana odpowiedź.jobs -p
powrócił tak samo jakjobs -l
na Lubuntu 16.4$$
to pid bieżącego skryptu$!
jest pid ostatniego procesu w tleOto przykładowy zapis z sesji bash (
%1
odnosi się do liczby porządkowej procesu w tle, jak widać zjobs
):źródło
%1
nie zwraca procesu w tle na moim Ubuntu, podczasecho $!
gdyJeszcze prostszy sposób na zabicie całego procesu potomnego skryptu bash:
-P
Flag działa w ten sam sposób zpkill
ipgrep
- robi się procesów potomnych, tylkopkill
procesy potomne zginąć izpgrep
PID dziecko są wypisywane na standardowe wyjście.źródło
bash -c 'bash -c "sleep 300 &"' &
uruchomieniupgrep -P $$
nic nie pokazuje, ponieważ sen nie będzie bezpośrednim dzieckiem twojej skorupy.$$
odnosi się do bieżącej powłoki.bash -c 'bash -c "sleep 300 &"' & ; pgrep -P $$
,[1] <pid>. So at least it shows something, but this is probably not the output of
wchodzę na standardowe wyjście pgrep`bash -c 'bash -c "sleep 10 & wait $!"' & sleep 0.1; pstree -p $$
to właśnie zrobiłem. Sprawdź to, mam nadzieję, że może pomóc.
Następnie po prostu uruchom go jako:
./bgkill.sh
oczywiście z odpowiednimi uprawnieniamiźródło
Możesz także użyć pstree:
Zwykle daje to tekstową reprezentację wszystkich procesów dla „użytkownika”, a opcja -p podaje identyfikator procesu. O ile rozumiem, nie zależy to od posiadania procesów przez bieżącą powłokę. Pokazuje także widelce.
źródło
pgrep
może uzyskać wszystkie podrzędne identyfikatory PID procesu nadrzędnego. Jak wspomniano wcześniej,$$
obecne skrypty PID. Tak więc, jeśli chcesz, aby skrypt, który czyści się po sobie, powinien załatwić sprawę:źródło
trap 'pkill -P $$' SIGING SIGTERM EXIT
wygląda na prostsze, ale go nie przetestowałem.SIG
prefiksu. Jest to dozwolone przez POSIX ale tylko jako przedłużenie że implementacje mogą wspierać: pubs.opengroup.org/onlinepubs/007904975/utilities/trap.html Skorupa kreska na przykład nie.