방금 시작한 프로세스의 pid를 얻는 방법


70

프로세스를 시작하고 (예 : myCommand) pid를 얻습니다 (나중에 죽일 수 있도록).

ps를 시도하고 이름으로 필터링했지만 이름으로 프로세스를 구별 할 수 없습니다

myCommand
ps ux | awk '/<myCommand>/ {print $2}' 

프로세스 이름이 고유하지 않기 때문입니다.

다음과 같은 방법으로 프로세스를 실행할 수 있습니다.

myCommand &

나는이 PID를 얻을 수 있음을 발견했다.

echo $!

더 간단한 해결책이 있습니까?

한 줄 명령의 결과로 myCommand를 실행하고 PID를 얻습니다.

답변:


77

무엇보다 간단 할 수 echo $!있습니까? 한 줄로 :

myCommand & echo $!

이 명령을 "&"와 병합하면 많은 도움이되었습니다.
rafalmag

8
bash 스크립트, 프로그램을 시작하는 루프, $! 정확하지 않습니다. 때로는 스크립트 자체의 pid를 반환하고 때로는 스크립트에서 grep 또는 awk가 실행 되어이 시나리오에서 방금 시작한 프로세스의 pid를 얻는 솔루션이 있습니까? pid =와 같은 myprogram멋진 것

2
NB를 사용 &하려면 이전 행으로 a 를 사용하여 명령을 시작해야합니다 . 그렇지 않으면 echo가 기본적으로 공백을 반환합니다.
rogerdpack

2
변수에 할당하는 것은 command & echo $!이 단계에서 실행을 정지시킵니다 :(
Shashank Vivek

26

작은 스크립트로 명령을 감싸십시오

#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file

20

당신은 사용할 수 있습니다 sh -cexec심지어 명령의 PID를 얻을 전에 이 실행됩니다.

myCommandPID가 실행되기 전에 인쇄되도록 시작하려면 다음을 사용할 수 있습니다.

sh -c 'echo $$; exec myCommand'

작동 방식 :

새 쉘을 시작하고 해당 쉘의 PID를 인쇄 한 다음 exec내장을 사용 하여 쉘을 명령 으로 대체 하여 동일한 PID 를 갖도록 합니다. 쉘은으로 명령을 실행하면 exec내장, 쉘입니다 실제로 되고 해당 명령 보다는, 보다 일반적인 행동 자체 별도의 PID를 가지고 다음 명령하게 자신의 새 복사본을 분기의.

비동기 실행 (with &), 작업 제어 또는을 사용하여 검색 하는 대안보다 훨씬 간단하다는 것을 알았 습니다 ps. 이러한 접근 방식은 문제가 없지만 명령을 사용해야하는 특정 이유가없는 경우 (예 : 명령이 이미 실행 중이거나 PID를 검색하거나 작업 제어를 사용하는 것이 합리적 임)이 방법을 먼저 고려하는 것이 좋습니다. (그리고 나는 이것을 달성하기 위해 복잡한 스크립트 또는 다른 프로그램을 작성하는 것을 고려하지 않을 것입니다).

이 답변 에는이 기술의 예가 포함되어 있습니다.


해당 명령의 일부를 생략 할 수도 있지만 일반적으로 그렇지는 않습니다.

사용중인 쉘이 Bourne 스타일이므로 exec이러한 의미를 가진 내장 기능 을 지원하더라도 일반적 으로이 목적을 위해 별도sh -c 의 새로운 쉘 프로세스 를 작성 하기 위해 (또는 이와 동등한) 사용하지 마십시오 .

  • 쉘이되면, myCommand후속 명령을 실행하기 위해 대기중인 쉘이 없습니다. sh -c 'echo $$; exec myCommand; foofoo교체 한 후 실행을 시도 할 수 없습니다 myCommand. 이 명령을 마지막 명령으로 실행하는 스크립트를 작성하지 않으면 echo $$; exec myCommand다른 명령을 실행하는 쉘 에서만 사용할 수 없습니다 .
  • 이를 위해 서브 쉘 을 사용할 수 없습니다 . (echo $$; exec myCommand)보다 구문 상으로는 좋을 수도 sh -c 'echo $$; exec myCommand'있지만, $$내부 ( )에서 실행할 때 하위 쉘 자체가 아닌 상위 쉘의 PID를 제공합니다. 그러나 새 명령의 PID가 서브 쉘의 PID입니다. 일부 쉘은 서브 쉘의 PID, 찾기 위해 자신이 아닌 휴대용 메커니즘을 제공 할 수있는 이 사용합니다. 특히, 배쉬 4 , (echo $BASHPID; exec myCommand)작동 않습니다.

마지막으로, 일부 쉘은 이후에 쉘이 아무 것도 수행 할 필요가없는 것으로 알려진 경우 명령을 실행하는 것처럼 최적화 를 수행합니다 exec(즉, 먼저 포크를 포기 함). 일부 쉘은 마지막으로 실행되는 명령 일 때마다이 작업을 수행하는 반면, 다른 쉘은 명령 전후에 다른 명령이 없을 때만 수행하고 다른 쉘에서는 전혀 수행하지 않습니다. 효과는 경우에하는 것은 작성하는 것을 잊지이다 exec그냥 사용 sh -c 'echo $$; myCommand'이됩니다 다음 때때로 당신에게 올바른 PID를주고 일부 와 시스템 일부 포탄입니다. 나는 그러한 행동에 의존 하지 말고 항상 exec그것이 필요할 때를 포함 하는 것이 좋습니다 .


을 실행하기 전에 myCommandbash 스크립트에서 여러 환경 변수를 설정해야합니다. 이것들은 exec명령이 실행 되는 환경으로 이어질까요?
user5359531

내 환경이 exec명령을 수행하는 것처럼 보입니다 . 그러나 myCommand다른 프로세스를 시작할 때는이 방법이 작동하지 않습니다. 다른 프로세스는 작업해야합니다. 이 방법으로 얻은 kill -INT <pid>위치를 발행 pid하면 신호가에 의해 시작된 하위 프로세스에 도달하지 않지만 현재 세션에서 myCommand실행 myCommand하고 Ctrl + C를 누르면 신호가 올바르게 전파됩니다.
user5359531

1
나는 이것을 시도했지만 myCommand 프로세스의 pid는 echo $$ +1의 pid 출력 인 것 같습니다. 내가 뭔가 잘못하고 있습니까?
crobar

내 명령은 다음과 같습니다.sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
crobar

7

더 간단한 해결책은 모르지만 $를 사용하지 않습니다! 충분하다? 나중에 다른 사람이 말했듯이 나중에 필요할 경우 다른 변수에 값을 할당 할 수 있습니다.

참고로 ps에서 파이핑하는 대신 pgrep또는을 사용할 수 있습니다 pidof.


5

pid를 파일에 등록한 후 bash 스크립트에서 exec를 사용하십시오.

예:

args p1, p2, p3으로 실행하려는 "forever.sh"라는 스크립트가 있다고 가정하십시오.

forever.sh 소스 코드 :

#!/bin/sh

while [ 1 -lt 2 ] ; do
    logger "$0 running with parameters \"$@\""
    sleep 5
done

reaper.sh를 작성하십시오.

#!/bin/sh

echo $$ > /var/run/$1.pid
exec "$@"

reaper.sh를 통해 forever.sh를 실행하십시오.

./reaper.sh ./forever.sh p1 p2 p3 p4 &

forever.sh는 5 초마다 syslog에 행을 기록하는 것 이상을 수행하지 않습니다.

이제 /var/run/forever.sh.pid에 pid가 있습니다.

cat /var/run/forever.sh.pid 
5780

forever.sh가 실행 중입니다. syslog grep :

Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"

프로세스 테이블에서 볼 수 있습니다.

ps axuwww|grep 'forever.sh p1' |grep -v grep
root      5780  0.0  0.0   4148   624 pts/7    S    16:07   0:00 /bin/sh ./forever.sh p1 p2 p3 p4

3
아, 그리고 "oneliner": / bin / sh -c 'echo $$> / tmp / my.pid && exec program args'&
user237419

1
인수에서 내부 공백을 올바르게 유지하려면 exec "$@"대신을 사용해야 합니다 exec $*. 기술적으로 보존해야 할 것은 공백이 아니라 IFS 셸 매개 변수의 문자 발생 (기본값은 공백, 탭 및 줄 바꿈)입니다.
Chris Johnsen

요점을 알았어. :)
user237419

감사합니다. $$ 매개 변수를 몰랐습니다. 매우 유용 할 수 있습니다.
rafalmag

3

bash 쉘에서 대안 $!jobs -p내장 되어 있을 수 있습니다 . 경우에 따라 변수 확장 전에 (또는 대신) 쉘 !에서 in $!을 해석하여 예기치 않은 결과가 발생합니다.

예를 들어, 작동하지 않습니다.

((yourcommand) & echo $! >/var/run/pidfile)

이 동안 :

((yourcommand) & jobs -p >/var/run/pidfile)

나는 당신이 ((yourcommand) & jobs -p> / var / run / pidfile)을 의미한다고 생각합니다.
Dom

1

다음과 같은 것을 사용할 수 있습니다.

$ myCommand ; pid=$!

또는

$ myCommand && pid=$!

두 개의 명령을 사용하여 관절 할 수 있습니다 ;또는 &&. 두 번째 경우, pid는 첫 번째 명령이 성공한 경우에만 설정됩니다. 에서 프로세스 ID를 얻을 수 있습니다 $pid.


3
OP는 PID를 가져 와서 나중에 죽일 수 있기를 원합니다. ; &&는 원래 프로세스가 echo $! 전에 종료되도록 요구합니다. 실행됩니다.
user9517

네, 맞아요. myCommand가 종료 된 후 pid를 제공합니다.
Khaled

6
$!이후에 참조 &&하거나 ;명령 분리기의 왼쪽에 대해 시작된 프로세스의 PID를 제공하지 않습니다. $!비동기 적으로 시작된 프로세스에 대해서만 설정됩니다 (예 : 일반적으로 &일부 쉘에는 다른 방법이 있음)
Chris Johnsen 9

도움이되고 왜 아무도 투표를하지 않습니까? 좋은 일이지만 :)
사원

1

이것은 약간의 해킹 답변이며 대부분의 사람들에게는 효과가 없을 것입니다. 또한 보안 위험이 큰 방법이므로 안전하고 입력이 위생적이며 확실하지 않으면 확실하지 않습니다.

작은 C 프로그램을 여기에 start(또는 원하는대로) 바이너리로 컴파일 한 다음 프로그램을 다음과 같이 실행하십시오../start your-program-here arg0 arg1 arg2 ...

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    if (argc >= 2)
    {
        printf("%lu\n", (long unsigned) getpid());
        if (execvp(argv[1], &argv[1]) < 0)
        {
            perror(NULL);
            return 127;
        }
    }
    return 0;
}

간단히 말해 PID를 인쇄 stdout한 다음 프로그램을 프로세스에로드합니다. 여전히 동일한 PID를 가져야합니다.


이 코드가 반환 한 PID 번호를 bash 변수에 어떻게 기록 할 수 있습니까? 나에게 불분명 한 이유 때문에, stdout이 예에 기록되어 있지 않은 것 같습니다 :RESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
Tfb9

@ Tfb9 : 다른 방법 중 하나를 정직하게 추천합니다. 나는 2 년 이상 전에 이것을 썼고 그것은 제시 된 해커 / 오류가 발생하기 쉬운 방법 중 하나입니다 (또는 그렇게 생각합니다).
tonysdg 1

메모 주셔서 감사합니다. 나는 이것으로 내 문제를 해결했다고 생각한다sleep 10 & PID_IS=$!; echo $PID_IS
Tfb9
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.