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.
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.
Odpowiedzi:
Musisz zapisać PID procesu w tle podczas jego uruchamiania:
foo &
FOO_PID=$!
# do other stuff
kill $FOO_PID
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.
foo
i $!
, i otrzymujemy, że coś jest pid zamiast zamiast foo
?
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
lub ps
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:28
Możesz użyć jobs -l
polecenia, aby dostać się do określonego zadaniaL
^Z
[1]+ Stopped guard
my_mac:workspace r$ jobs -l
[1]+ 46841 Suspended: 18 guard
W tym przypadku 46841 jest PID.
Od help jobs
:
-l Zgłoś identyfikator grupy procesów i katalog roboczy zadań.
jobs -p
to kolejna opcja, która pokazuje tylko PID.
$!
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 jak jobs -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ć z jobs
):
$ echo $$
3748
$ sleep 100 &
[1] 192
$ echo $!
192
$ kill %1
[1]+ Terminated sleep 100
%1
nie zwraca procesu w tle na moim Ubuntu, podczas echo $!
gdy
Jeszcze prostszy sposób na zabicie całego procesu potomnego skryptu bash:
pkill -P $$
-P
Flag działa w ten sam sposób z pkill
i pgrep
- robi się procesów potomnych, tylko pkill
procesy potomne zginąć iz pgrep
PID dziecko są wypisywane na standardowe wyjście.
bash -c 'bash -c "sleep 300 &"' &
uruchomieniu pgrep -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.
#!/bin/bash
#
# So something to show.
echo "UNO" > UNO.txt
echo "DOS" > DOS.txt
#
# Initialize Pid List
dPidLst=""
#
# Generate background processes
tail -f UNO.txt&
dPidLst="$dPidLst $!"
tail -f DOS.txt&
dPidLst="$dPidLst $!"
#
# Report process IDs
echo PID=$$
echo dPidLst=$dPidLst
#
# Show process on current shell
ps -f
#
# Start killing background processes from list
for dPid in $dPidLst
do
echo killing $dPid. Process is still there.
ps | grep $dPid
kill $dPid
ps | grep $dPid
echo Just ran "'"ps"'" command, $dPid must not show again.
done
Następnie po prostu uruchom go jako: ./bgkill.sh
oczywiście z odpowiednimi uprawnieniami
root@umsstd22 [P]:~# ./bgkill.sh
PID=23757
dPidLst= 23758 23759
UNO
DOS
UID PID PPID C STIME TTY TIME CMD
root 3937 3935 0 11:07 pts/5 00:00:00 -bash
root 23757 3937 0 11:55 pts/5 00:00:00 /bin/bash ./bgkill.sh
root 23758 23757 0 11:55 pts/5 00:00:00 tail -f UNO.txt
root 23759 23757 0 11:55 pts/5 00:00:00 tail -f DOS.txt
root 23760 23757 0 11:55 pts/5 00:00:00 ps -f
killing 23758. Process is still there.
23758 pts/5 00:00:00 tail
./bgkill.sh: line 24: 23758 Terminated tail -f UNO.txt
Just ran 'ps' command, 23758 must not show again.
killing 23759. Process is still there.
23759 pts/5 00:00:00 tail
./bgkill.sh: line 24: 23759 Terminated tail -f DOS.txt
Just ran 'ps' command, 23759 must not show again.
root@umsstd22 [P]:~# ps -f
UID PID PPID C STIME TTY TIME CMD
root 3937 3935 0 11:07 pts/5 00:00:00 -bash
root 24200 3937 0 11:56 pts/5 00:00:00 ps -f
Możesz także użyć pstree:
pstree -p user
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.
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ę:
trap 'kill $( pgrep -P $$ | tr "\n" " " )' SIGINT SIGTERM EXIT
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.