백그라운드 프로세스의 프로세스 ID를 얻는 방법은 무엇입니까?


375

쉘 스크립트에서 백그라운드 프로세스를 시작하고 스크립트가 끝나면이 프로세스를 종료하고 싶습니다.

쉘 스크립트에서이 프로세스의 PID를 얻는 방법은 무엇입니까? 내가 볼 수있는 한 변수 $!에는 백그라운드 프로세스가 아닌 현재 스크립트의 PID가 포함되어 있습니다.


8
$! 맞다. BG에서 스크립트를 시작 하시겠습니까? 샘플주세요.
pixelbeat

7
예 $! 맞다. 내가 틀렸어.
Volodymyr Bezuglyy 2009

11
$$는 현재 스크립트 PID를 포함합니다.
HUB

답변:


583

시작할 때 백그라운드 프로세스의 PID를 저장해야합니다.

foo &
FOO_PID=$!
# do other stuff
kill $FOO_PID

작업 제어는 대화식 기능이며 제어 터미널에 연결되어 있으므로 작업 제어를 사용할 수 없습니다. 스크립트에는 터미널이 전혀 연결되어 있지 않아도되므로 작업 제어가 반드시 필요한 것은 아닙니다.


22
$ 이후! 마지막 백그라운드 프로세스의 pid를 반환합니다. foo와 사이에 무언가가 시작될 수 있습니까? $!그리고 우리는 그 대신에 pid를 얻습니다 foo.
WiSaGaN

53
@WiSaGaN : 아니요. 그 라인들 사이에는 아무 것도 없습니다. 시스템의 다른 활동은 이에 영향을 미치지 않습니다. $! 해당 쉘에서 마지막 백그라운드 프로세스의 PID로 확장됩니다 .
camh

8
... foo여러 개의 배관 명령 (예 :)이 발생하는 경우 호스를 사용하십시오 tail -f somefile.txt | grep sometext. 그러한 경우, $!찾고자하는 경우 tail 명령 대신 grep 명령의 PID를 얻을 수 있습니다. 이 경우 jobs또는 등 을 사용해야 ps합니다.
John Rix

1
@JohnRix : 반드시 그런 것은 아닙니다. 당신은 pid를 얻지 grep만 그것을 죽이면 tail은 파이프에 쓰려고 할 때 SIGPIPE를 얻습니다. 그러나 까다로운 프로세스 관리 / 제어를 시도하자마자 bash / shell은 상당히 고통스러워집니다.
camh

5
또 다른 가치 액 (에 대한 답변에 대한 코멘트)에서 제안 하는 방법 막 시작 프로세스의 PID하려면 : 아, 그리고 "oneliner" /bin/sh -c 'echo $$>/tmp/my.pid && exec program args' &sysfault 11월 24일 '10 14시 28분에서 -
IMZ - 이반 Zakharyaschev

148

jobs -l명령을 사용하여 특정 작업을 수행 할 수 있습니다

^Z
[1]+  Stopped                 guard

my_mac:workspace r$ jobs -l
[1]+ 46841 Suspended: 18           guard

이 경우 PID는 46841입니다.

보낸 사람 help jobs:

-l 프로세스 그룹 ID 및 작업의 작업 디렉토리를보고하십시오.

jobs -p PID 만 보여주는 또 다른 옵션입니다.


쉘 스크립트에서 이것을 사용하려면 출력을 처리해야합니다.
Phil

6
@Phil pid 만 나열하려면 : jobs -p. 특정 작업의 pid를 나열하려면 다음을 수행하십시오. jobs -p % 3. 출력을 처리 할 필요가 없습니다.
Erik Aronesty

1
다른 명령 / 인수를 사용하여 @Erik 내 의견의 컨텍스트를 변경합니다. 추가 인수가 없으면 출력에 처리가 필요합니다. 답변 개선을 제안하십시오!
Phil

PID $!를 시작한 직후 부터 저장하면 대부분의 상황에서 이식성이 더 쉽고 간단합니다. 이것이 현재 받아 들여지는 대답입니다.
tripleee

jobs -pjobs -lLubuntu 16.4
Timo

46
  • $$ 현재 스크립트의 pid입니다
  • $! 마지막 배경 프로세스의 pid입니다

bash 세션의 샘플 대본은 다음과 같습니다 (에서 %1본 백그라운드 프로세스의 서수를 나타냅니다 jobs).

$ echo $$
3748

$ sleep 100 &
[1] 192

$ echo $!
192

$ kill %1

[1]+  Terminated              sleep 100

에코는 %1반면, 우분투의 백그라운드 프로세스를 반환하지 않습니다 echo $!않습니다
티모

25

bash 스크립트의 모든 자식 프로세스를 종료하는 더 간단한 방법 :

pkill -P $$

-P플래그와 동일한 방식으로 작동 pkill하고 pgrep만 함께, 자식 프로세스를 가져옵니다 - pkill와 자식 프로세스가 사망하고 얻을 pgrep자식의 PID가 표준 출력에 인쇄됩니다.


매우 편리합니다! 이것은 열린 프로세스를 백그라운드에 두지 않는 가장 좋은 방법입니다.
lepe

@lepe :별로. 조부모라면 작동하지 않습니다. 수면이 쉘의 직접적인 자식이 아니기 때문에 bash -c 'bash -c "sleep 300 &"' & 달리기 후에 pgrep -P $$는 아무것도 보이지 않습니다.
petre

1
@AlexeyPolonsky : 스크립트가 아닌 쉘의 모든 자식 프로세스를 종료하십시오. 때문에이 $$현재 쉘을 의미합니다.
Timo

공연 bash -c 'bash -c "sleep 300 &"' & ; pgrep -P $$, 나는 stdout [1] <pid>. So at least it shows something, but this is probably not the output of pgrep에 도착
Timo

프로세스조차도 부모 프로세스에서 분리 할 수 ​​있습니다. 간단한 트릭은 포크를 불러서 (손자를 만들) 손자가 계속 작업을하는 동안 자식 프로세스를 종료하도록하는 것입니다. (데몬은 키워드입니다.) 그러나 아이가 계속 달리더라도 pkill -P는 신호를 손자에게 전파하기에 충분하지 않습니다. pstree와 같은 도구는 전체 종속 프로세스 트리를 따라야합니다. 그러나 이것은 부모가 프로세스 1이므로 프로세스에서 시작된 데몬을 잡을 수 없습니다. 예 :bash -c 'bash -c "sleep 10 & wait $!"' & sleep 0.1; pstree -p $$
Pauli Nieminen

4

이것이 내가 한 일입니다. 그것을 확인하고 도움이되기를 바랍니다.

#!/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

그런 다음 ./bgkill.sh적절한 권한 으로 실행하십시오.

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

3

pstree를 사용할 수도 있습니다 :

pstree -p user

이것은 일반적으로 "user"에 대한 모든 프로세스의 텍스트 표현을 제공하고 -p 옵션은 process-id를 제공합니다. 내가 이해하는 한 현재 쉘이 프로세스를 소유하게하는 것은 의존하지 않습니다. 포크도 표시됩니다.


1
쉘 스크립트에서 이것을 사용하려면, 출력을 많이 처리해야합니다.
Phil

1

pgrep부모 프로세스의 모든 자식 PID를 얻을 수 있습니다. 앞에서 언급했듯이 $$현재 스크립트 PID입니다. 따라서 자체적으로 정리되는 스크립트를 원한다면 다음과 같은 트릭을 수행해야합니다.

trap 'kill $( pgrep -P $$ | tr "\n" " " )' SIGINT SIGTERM EXIT

이것이 많이 죽이지 않습니까?
Phil

이 것 네, 문제는 유지 언급 한 적이 번 출구에 살아 배경 아이들.
errant.info

trap 'pkill -P $$' SIGING SIGTERM EXIT더 단순 해 보이지만 테스트하지는 않았습니다.
petre

호환성을 위해 SIG접두사를 사용하지 마십시오 . POSIX에서 허용하지만 구현에서 지원할 있는 확장으로 다음과 같습니다. pubs.opengroup.org/onlinepubs/007904975/utilities/trap.html 예를 들어 대시 셸 지원 하지 않습니다.
josch
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.