신청서를 작성 중입니다. 다양한 외부 프로세스를 생성하는 기능이 있습니다. 애플리케이션이 닫힐 때 생성된 모든 프로세스를 종료하고 싶습니다.
쉬운 것 같죠? 내 PID를 찾아 프로세스 트리를 반복적으로 탐색하여 상향식으로 보이는 모든 것을 종료합니다.
그러나 이것은 그렇지 않습니다일하다. 한 가지 특별한 경우에는 를 빌드했지만 foo
방금 foo
빌드 bar
한 다음 즉시 종료하여 bar
실행 상태로 두었습니다. 있다어떤 기록도 없다실제로 이는 bar
애플리케이션 프로세스 트리의 일부였습니다. 따라서 애플리케이션은 를 종료해야 하는지 알 수 있는 방법이 없습니다 bar
.
나는 이것을 시도한 지구상 최초의 사람이 될 수 없다고 확신합니다. 그렇다면 표준 솔루션은 무엇입니까? 나는 프로세스가 생성하는 모든 프로세스가 무조건 동일한 태그를 상속하도록 프로세스에 "태그"를 지정하는 방법을 찾고 있다고 생각합니다.
(지금까지 제가 생각할 수 있는 최선은 다른 사용자로 응용 프로그램을 실행하는 것입니다. 그렇게 하면 해당 사용자에 속한 모든 프로세스를 무차별적으로 종료할 수 있습니다. 하지만 이로 인해 온갖 종류의 액세스 권한 문제가 발생합니다...)
답변1
고쳐 쓰다
이것은 분명히 질문을 더 주의 깊게 읽어야 했던 질문 중 하나입니다(비록 이 질문에 대한 대부분의 답변이 그런 것 같지만). 질문의 요점을 분명히 놓쳤음에도 불구하고 좋은 정보를 제공하므로 원래 답변을 유지하고 있습니다.
SID 사용
여기서 (적어도 Linux의 경우) 가장 다양하고 안정적인 접근 방식은 PPID나 PGID 대신 SID(세션 ID)를 사용하는 것입니다. 이는 하위 프로세스에 의해 변경될 가능성이 없으며 쉘 스크립트의 경우 이 setsid
명령을 사용하여 새 세션을 시작할 수 있습니다. setuid
시스템 호출은 셸 외부에서 사용할 수 있습니다.
세션 리더인 셸의 경우 다음을 수행하여 세션의 다른 모든 프로세스를 종료할 수 있습니다(셸은 자체적으로 종료되지 않음).
kill $(ps -s $$ -o pid=)
참고: 매개변수의 후행 등호는 열 헤더를 pid=
제거합니다 .PID
그렇지 않으면 시스템 호출을 사용하여 getsid
각 프로세스를 호출하는 것이 유일한 방법인 것 같습니다.
PID 네임스페이스 사용
가장 안정적인 방법이지만 Linux에서만 작동하고 루트 권한이 필요하다는 단점이 있습니다. 또한 쉘 도구(사용된 경우)는 매우 새롭고 아직 널리 사용되지 않습니다.
PID 네임스페이스에 대한 자세한 내용은 다음 질문을 참조하세요."nsenter:"를 사용하여 하위 프로세스를 감옥에 두는 안정적인 방법. 여기서 기본적인 접근 방식은 시스템 호출 CLONE_NEWPID
과 함께 (또는 명령을 통해) 플래그를 사용하여 새 PID 네임스페이스를 생성하는 것입니다.clone
unshare
PID 네임스페이스의 프로세스가 고아가 되면(즉, 상위 프로세스가 완료되면) 대신 최상위 PID 네임스페이스 프로세스의 상위가 됩니다 init
. 이는 프로세스를 탐색하여 항상 최상위 프로세스를 식별할 수 있음을 의미합니다. tree 프로세스의 모든 하위 항목입니다. 쉘 스크립트의 경우 아래 PPID 방법은 모든 하위 항목을 안정적으로 종료합니다.
PID 네임스페이스에 대한 추가 정보:
원래 답변
하위 프로세스 종료
pkill
( 사용 가능한 경우) 쉘 스크립트에서 이를 수행하는 쉬운 방법은 다음과 같습니다.
pkill -P $$
이는 현재 주어진 프로세스의 모든 하위 프로세스를 종료합니다( $$
현재 쉘의 PID로 확장됨).
모든 하위 프로세스 종료
또는 현재 쉘 프로세스의 모든 하위 프로세스와 직계 하위 프로세스를 종료할 수도 있습니다. 이 경우 다음 재귀 셸 함수를 사용하여 모든 하위 PID를 나열한 다음 이를 인수로 전달하여 종료할 수 있습니다.
list_descendants ()
{
local children=$(ps -o pid= --ppid "$1")
for pid in $children
do
list_descendants "$pid"
done
echo "$children"
}
kill $(list_descendants $$)
더블 포크
한 가지 주목해야 할 점은 이중 기법으로 인해 위의 방법이 예상대로 작동하지 않을 수 있다는 것입니다 fork()
. 이는 일반적으로 프로세스를 데몬화할 때 사용됩니다. 이름에서 알 수 있듯이 시작될 프로세스는 원래 프로세스의 두 번째 분기에서 실행됩니다. 프로세스가 시작되면 첫 번째 분기가 종료됩니다. 이는 프로세스가 고아가 됨을 의미합니다.
init
이 경우 해당 프로세스를 시작한 원래 프로세스가 아닌 프로세스의 하위 프로세스가 됩니다 . 어떤 프로세스가 원래 상위 프로세스인지 식별할 수 있는 신뢰할 수 있는 방법이 없으므로, 이 경우 다른 식별 방법(예: PID 파일) 없이는 해당 프로세스를 종료할 수 없습니다. 그러나 이 기술을 사용한 경우 정당한 이유 없이 프로세스를 종료하려고 시도해서는 안 됩니다.
추가 자료:
답변2
당신은 그것을 사용할 수 있습니다 :
kill -TERM -- -XXX
XXX
종료할 프로세스 그룹의 그룹 번호는 어디에 있습니까? 다음을 사용하여 확인할 수 있습니다.
$ ps x -o "%p %r %c"
PID PGID COMMAND
2416 1272 gnome-keyring-d
2427 2427 gnome-session
2459 2427 lightdm-session <defunct>
2467 2467 ssh-agent
2470 2427 dbus-launch
2471 2471 dbus-daemon
2484 2427 gnome-settings-
2489 2471 gvfsd
2491 2471 gvfs-fuse-daemo
2499 2427 compiz
2502 2471 gconfd-2
2508 2427 syndaemon
2513 2512 pulseaudio
2517 2512 gconf-helper
2519 2471 gvfsd-metadata
프로세스 그룹 ID에 대한 자세한 내용은 다음을 확인하세요 man setpgid
.
DESCRIPTION
All of these interfaces are available on Linux, and are used for get‐
ting and setting the process group ID (PGID) of a process. The pre‐
ferred, POSIX.1-specified ways of doing this are: getpgrp(void), for
retrieving the calling process's PGID; and setpgid(), for setting a
process's PGID.
setpgid() sets the PGID of the process specified by pid to pgid. If
pid is zero, then the process ID of the calling process is used. If
pgid is zero, then the PGID of the process specified by pid is made the
same as its process ID. If setpgid() is used to move a process from
one process group to another (as is done by some shells when creating
pipelines), both process groups must be part of the same session (see
setsid(2) and credentials(7)). In this case, the pgid specifies an
existing process group to be joined and the session ID of that group
must match the session ID of the joining process.
답변3
상위 프로세스 PID를 알고 있으면 이를 수행하는 데 사용할 수 있습니다 pkill
.
예
$ pkill -TERM -P 27888
PPID는 27888입니다.
pkill people에서 발췌
-P, --parent ppid,...
Only match processes whose parent process ID is listed.
스크립트에서 내 PID는 무엇입니까?
$$
이것은 아마도 다음 질문일 것입니다. 따라서 Bash 스크립트를 사용하는 경우 상단을 사용하여 스크립트의 PID를 찾을 수 있습니다.
예
다음 스크립트가 있다고 가정해 보겠습니다.
$ more somescript.bash
#!/bin/bash
echo "top: $$"
sleep 5
echo "bottom: $$"
이제 백그라운드에서 실행합니다.
$ ./somescript.bash &
[2] 28007
top: 28007
보세요. pgrep
올바른 PID를 얻었습니다.
$ pgrep somescript.bash
28007
$ bottom: 28007
[2]+ Done ./somescript.bash
프로세스의 PGID 사용
이 명령을 사용하면 ps
프로세스를 종료하는 데 사용할 수 있는 프로세스 PGID를 찾을 수 있습니다.
이제 다음 스크립트를 사용하십시오 killies.bash
.
$ more killies.bash
#!/bin/bash
sleep 1000 &
sleep 1000 &
sleep 1000 &
sleep 100
우리는 다음과 같이 실행합니다:
$ killies.bash &
확인하다:
$ ps x -o "%p %r %c"
PID PGID COMMAND
28367 28367 killies.bash
28368 28367 sleep
28369 28367 sleep
28370 28367 sleep
28371 28367 sleep
이제 PGID를 종료합니다.
$ pkill -TERM -g 28367
[1]+ Terminated ./killies.bash
추가 방법
이 SO Q&A를 보면 원하는 것을 달성하는 더 많은 방법을 찾을 수 있습니다.
인용하다
답변4
${PROC_CMD} &
pid=$!
kids=$(grep -l "PPid.*$$" /proc/*/status | grep -o "[0-9]*"
for kid in $(cat /proc/$pid/task/*/children); do
kids="$kid $kids $(cat /proc/$kid/task/*/children)"
done
printf '%s ' $kids)
kill $kids
이렇게 하면 ${PROC_CMD},
첫 번째 행의 배경에 있는 모든 자식이 죽고 $pid
다음 행에서 캡처됩니다.
cat /proc/$pid/task/*/children
위에는 하위 프로세스만 나열되어 있습니다.
과정을 기억하는 것이 중요하다탈출할 수 있다예를 들어 $PPID.
:
echo $( grep "Pid" /proc/self/status & )
Pid: 349 PPid: 1 TracerPid: 0