고쳐 쓰다

고쳐 쓰다

신청서를 작성 중입니다. 다양한 외부 프로세스를 생성하는 기능이 있습니다. 애플리케이션이 닫힐 때 생성된 모든 프로세스를 종료하고 싶습니다.

쉬운 것 같죠? 내 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 네임스페이스를 생성하는 것입니다.cloneunshare

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

관련 정보