우아하게 하위 프로세스 목록을 얻습니다.


23

에서 내려 오는 모든 프로세스 (예 : 어린이, 손자 등) 목록을 얻고 싶습니다 $pid. 이것이 내가 생각해 낸 가장 간단한 방법입니다.

pstree -p $pid | tr "\n" " " |sed "s/[^0-9]/ /g" |sed "s/\s\s*/ /g"

모든 하위 프로세스 의 전체 목록을 가져 오는 명령이나 간단한 방법이 있습니까?


한 줄에 모두 필요한 이유가 있습니까? 그 결과로 무엇을하고 있습니까? 나는 이것이 xy 문제라는 느낌을 가지고 있으며, 당신은 잘못된 질문을하고 있습니다.
jordanm

깨끗한 한 형식에 대해서는 신경 쓰지 않습니다 (즉, '\n'구분 대 ' '구분에 신경 쓰지 않습니다 ). 실제 사용 사례는 다음과 같다. a) 내가 순수 마조히즘으로 작성한 데몬 타이 저 스크립트 (특히, "중지"기능은 데몬 화 된 프로세스가 생성 한 모든 프로세스 트리를 처리해야한다); 및 b)는 타이밍 된-에서 어떤 프로세스가 생성 관리 죽일 시간 제한 스크립트.
STENyaK

2
@STenyaK 유스 케이스를 사용하면 프로세스 그룹과에 대한 부정적인 주장을 찾고 있다고 생각합니다 kill. 참조 unix.stackexchange.com/questions/9480/... , unix.stackexchange.com/questions/50555/...은
질 'SO-정지되는 악'

@Gilles를 사용 하면 죽이고 싶은 정확한 하위 트리 ps ax -opid,ppid,pgrp,cmd와 동일한 프로세스를 많이 볼 수 있습니다 pgrp. (또한, 나는 setpgrp데비안 꾸러미 꾸러미의 어느 곳에서나 프로그램을 볼 수 없다 : packages.debian.org/… )
STenyaK

1
또 다른 사용 사례 : 큰 병렬 빌드와 같이 너무 많은 리소스를 소비하는 전체 프로세스 트리에서 renice / ionice.
치타

답변:


15

다음은 다소 단순하며 명령 이름에서 숫자를 무시하는 이점이 있습니다.

pstree -p $pid | grep -o '([0-9]\+)' | grep -o '[0-9]\+'

또는 Perl과 함께 :

pstree -p $pid | perl -ne 'print "$1\n" while /\((\d+)\)/g'

우리는 괄호 안의 숫자를 찾고 있으므로 예를 들어 2를 자식 프로세스로 제공하지 않습니다 gif2png(3012). 그러나 명령 이름에 괄호 안에 숫자가 있으면 모든 베팅이 해제 된 것입니다. 지금까지는 텍스트 처리 만 가능합니다.

또한 프로세스 그룹이 갈 길이라고 생각합니다. 자체 프로세스 그룹에서 프로세스를 실행하려면 데비안 패키지 'daemontools'에서 'pgrphack'도구를 사용할 수 있습니다.

pgrphack my_command args

또는 다시 Perl을 켤 수 있습니다.

perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args

여기서 유일하게주의해야 할 점은 프로세스 그룹이 중첩되지 않기 때문에 일부 프로세스가 자체 프로세스 그룹을 작성하는 경우 해당 하위 프로세스는 더 이상 사용자가 작성한 그룹에 속하지 않는 것입니다.


자식 프로세스는 임의적이며 프로세스 그룹 자체를 사용하거나 사용하지 않을 수 있습니다 (아무것도 가정 할 수 없음). 그러나 당신의 대답은 리눅스에서 달성 할 수있는 Seesm에 가장 가깝기 때문에 받아 들일 것입니다. 감사.
STENYAK

이것은 매우 유용했습니다!
Michal Gallovic

pstree 파이프에는 스레드 ID, 즉 $ pid가 시작한 스레드의 ID도 포함됩니다.
maxschlepzig

단일 그렙을 사용할 수 있습니다.pstree -lp | grep -Po "(?<=\()\d+(?=\))"
puchu

7
descendent_pids() {
    pids=$(pgrep -P $1)
    echo $pids
    for pid in $pids; do
        descendent_pids $pid
    done
}

이것이 현대 쉘에서 작동 할 것이라고 지적 만 가치가있을 것입니다 ( bash, zsh, fish, 심지어 ksh 99), 그러나 수도 이전 껍질하지 작업, 예를 들면ksh 88
grochmal

@grochmal, ksh-88에서 작동하는 순회 솔루션에 대해서는 아래 답변을 참조하십시오.
maxschlepzig 2018 년

1

내가 찾은 가장 짧은 버전은 pop3d다음 과 같은 명령을 올바르게 처리합니다 .

pstree -p $pid | perl -ne 's/\((\d+)\)/print " $1"/ge'

다음과 같은 이상한 이름을 가진 명령이 있으면 잘못 처리됩니다 my(23)prog.


1
pstree가 해당 ID를 인쇄하기 때문에 일부 스레드를 실행하는 명령에는 작동하지 않습니다.
maxschlepzig

@maxschlepzig ffmpeg스레드 사용에 매우 문제가 있음을 알았습니다 . 그러나 빠른 관찰을 통해 스레드 이름이 중괄호 안에 표시되는 것처럼 보입니다 { }.
집시 Spellweaver

1

정확성 문제도 있습니다. 결과를 순진하게 파싱하는 pstree것은 여러 가지 이유로 문제가 있습니다.

  • pstree는 PID 스레드 ID를 표시합니다 (이름은 중괄호로 표시됨)
  • 명령 이름에는 중괄호, 괄호 안의 숫자를 포함하여 안정적인 구문 분석이 불가능할 수 있습니다.

Python과 psutil패키지가 설치되어있는 경우이 스 니펫을 사용하여 모든 하위 프로세스를 나열 할 수 있습니다.

pid=2235; python3 -c "import psutil
for c in psutil.Process($pid).children(True):
  print(c.pid)"

(예를 들어 psutil 패키지는 tracerFedora / CentOS에서 사용 가능한 명령 의 종속성으로 설치됩니다 .)

또는 Bourne 쉘에서 프로세스 트리의 너비 우선 탐색을 수행 할 수 있습니다.

ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); \
  done | tail -n +2 | tr " " "\n"

pid의 전이 폐쇄를 계산하기 위해, 꼬리 부분은 생략 될 수있다.

위의 내용은 재귀를 사용하지 않으며 ksh-88에서도 실행됩니다.

Linux에서는 pgrep호출을 제거 하고 대신 다음 정보를 읽을 수 있습니다 /proc.

ps=2235; while [ "$ps" ]; do echo $ps ; \
  ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done \
  | tr " " "\n"' | tail -n +2

각 PID 당 하나의 포크 / 실행을 저장 pgrep하고 각 호출에서 추가 작업을 수행하기 때문에보다 효율적 입니다.


1

이 Linux 버전에는 / proc 및 ps 만 필요합니다. @maxschlepzig의 훌륭한 답변 의 마지막 부분에서 수정되었습니다 . 이 버전은 루프에서 하위 프로세스를 생성하는 대신 셸에서 직접 / proc를 읽습니다. 이 글타래 제목이 요청하는 것처럼 조금 빠르며 약간 더 우아합니다.

#!/bin/dash

# Print all descendant pids of process pid $1
# adapted from /unix//a/339071

ps=${1:-1}
while [ "$ps" ]; do
  echo $ps
  unset ps1 ps2
  for p in $ps; do
    read ps2 < /proc/$p/task/$p/children 2>/dev/null
    ps1="$ps1 $ps2"
  done
  ps=$ps1
done | tr " " "\n" | tail -n +2

0

두 가지 (아주 인공적인) 유스 케이스 각각에서 왜 불행한 프로세스의 하위 프로세스를 죽이고 싶습니까? 자녀가 살거나 죽어야하는 과정보다 어떻게 더 잘 아십니까? 이것은 나에게 나쁜 디자인처럼 보입니다. 프로세스 자체가 정리되어야합니다.

당신이 정말로 더 잘 알고 있다면, 당신은이 서브 프로세스들을 분기시켜야하고, '데몬 화 된 프로세스'는 믿을 수 없을 정도로 너무 멍청합니다 fork(2).

예를 들어 @Gilles에서 제안한대로 하위 프로세스를 별도의 프로세스 그룹에 두는 등 프로세스 트리를 통해 하위 프로세스 목록을 유지하거나 그루 빙하는 것을 피해야합니다.

어쨌든, 나는 당신의 데몬 처리 된 프로세스가 깊은 서브 서브 서브 프로세스 트리보다 작업자 스레드 풀 (포함 프로세스와 함께 죽는)을 만드는 것이 낫다고 생각합니다. .


2
두 가지 사용 사례 모두 지속적인 통합 / 테스트 환경에서 사용되므로 자식 프로세스에 존재하는 버그의 가능성을 처리해야합니다. 내가 할 수있는 방법이 필요하므로이 버그는 제대로 종료 자신이나 자녀에게 무능력으로 표출 할 수 있도록 내가 최악의 경우에 그들 모두를 닫을 수 있습니다.
STENYAK

1
이 경우에는 @Gilles 및 @Jander와 함께 있습니다. 프로세스 그룹이 가장 좋은 방법입니다.
AnotherSmellyGeek

0

다음은 pgrep을 사용하고 동시에 모든 하위 항목을 가져올 수있는 pgrep 래퍼 스크립트입니다.

~/bin/pgrep_wrapper:

#!/bin/bash

# the delimiter argument must be the first arg, otherwise it is ignored
delim=$'\n'
if [ "$1" == "-d" ]; then
    delim=$2
    shift 2
fi

pids=
newpids=$(pgrep "$@")
status=$?
if [ $status -ne 0 ]; then
    exit $status
fi

while [ "$pids" != "$newpids" ]; do
    pids=$newpids
    newpids=$( { echo "$pids"; pgrep -P "$(echo -n "$pids" | tr -cs '[:digit:]' ',')"; } | sort -u )
done
if [ "$delim" != $'\n' ]; then
    first=1
    for pid in $pids; do
        if [ $first -ne 1 ]; then
            echo -n "$delim"
        else
            first=0
        fi  
        echo -n "$pid"
    done
else
    echo "$pids"
fi

pgrep_recursive -U $USER java현재 사용자로부터 모든 Java 프로세스 및 하위 프로세스를 찾는 것과 같은 일반적인 pgrep을 호출하는 것과 같은 방식으로 호출하십시오 .


1
이것은 배쉬이므로, PID를 분리 문자와 결합하는 데 사용되는 코드를 설정 IFS및 배열 ( "${array[*]}") 로 대체 할 수 있다고 생각 합니다.
muru
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.