마지막 백그라운드 애플리케이션의 PID를 얻는 방법

마지막 백그라운드 애플리케이션의 PID를 얻는 방법

이 질문에서:쉘 스크립트에서 마지막으로 실행된 명령의 pid를 얻는 방법은 무엇입니까?

스레딩은 훌륭하고 명확하지만 명령이 백그라운드에서 실행되기 위해 실제로 끝에 "&"가 필요하지 않으면 어떻게 될까요? 그렇다면 PID를 얻을 수 있습니까?

ps참고: 나는 and 를 사용하고 싶지 않습니다 grep. 이론적으로 프로세스의 PID는 명령을 실행한 후에 찾아야 하기 때문에 이 질문을 합니다.

백그라운드 앱의 예 - 이것은 내가 필요한 것이 아닙니다. 자체적으로 백그라운드로 들어가는 모든 것에 대한 일반적인 솔루션이 필요합니다(누군가 "전경" 옵션이 전혀 없도록 강제함). 그러나 솔루션을 테스트하려면 다음을 수행하십시오. 훌륭하게 작동할 것입니다:

내 애플리케이션 스크립트:

#!/bin/bash

(
sleep 10
echo test
sleep 5
) &

보시다시피 '&'는 스크립트 외부가 아닌 내부에 있으므로 스크립트를 시작하는 데 &가 필요하지 않습니다.

./my-app ; echo $! | od -c ; jobs | od -c
0000000  \n
0000001
0000000

$! null이고 jobs아무것도 반환하지 않습니다. 10초 후에도 "TEST" 메시지가 계속 나타납니다.

ps x | grep my-app | grep -v grep        
14986 pts/5    S      0:00 /bin/bash ./my-app

업데이트, bash 작업이 여기서 작동하지 않는다는 일부 의견이 나온 후 해결책을 찾고자 하며 내 희망은 bash에만 국한되지 않습니다.

답변1

도착하다배경자체적으로 애플리케이션은 하위 프로세스를 분기하고 상위 프로세스를 종료합니다. 쉘은 명령 자체를 실행하기 전에 분기된 프로세스이기 때문에 상위 프로세스에 대해 알고 있지만 해당 프로세스가 생성될 수 있는 하위 또는 손자를 볼 수 있는 방법은 없습니다.

이러한 백그라운드 명령의 더 간단한 예는 다음과 같습니다.

$ sh -c 'ps -j; sleep 10 &'
  PID  PGID   SID TTY          TIME CMD
 6562  6562 14469 pts/13   00:00:00 sh
 6563  6562 14469 pts/13   00:00:00 ps
14469 14469 14469 pts/13   00:00:00 zsh

나는 프로세스와 해당 프로세스 그룹을 zsh이해합니다 .sh

그러나 보이는 것은 6562개의 프로세스 종료뿐입니다. 6562 프로세스가 6563 프로세스를 생성했는지 여부를 알 수 있는 방법이 없습니다.

$ ps -j
  PID  PGID   SID TTY          TIME CMD
 6564  6562 14469 pts/13   00:00:00 sleep
 6565  6565 14469 pts/13   00:00:00 ps
14469 14469 14469 pts/13   00:00:00 zsh

그러나 실행 중인 프로세스도 해당 6562 프로세스 그룹에 있음을 알 수 있습니다 sleep(단, 명령이 새 프로세스 그룹 또는 세션을 시작하는 것을 중지할 수 있는 방법은 없습니다(일반적으로 데몬이 수행하는 것처럼)).

이러한 프로세스 그룹은 셸 상호 작용 중에만 생성됩니다.

당신이 할 수 있는 또 다른 일은 다음과 같습니다:

cmd | cat &
wait

cmd에 의해 생성된 프로세스가 표준 출력을 닫지 않으면 cat모두 죽을 때까지 죽지 않습니다.

답변2

이는 일반적으로 불가능합니다. 귀하의 특정한 경우에는 이것이 가능할 수 있습니다.

백그라운드 명령을 실행한 후 프로세스 ID를 검색할 수 있습니다.부모님으로부터. 전경 명령(메인 프로그램의 서브루틴)을 실행하고 해당 명령이 차례로 배경 명령(메인 프로그램의 손자)을 실행하는 경우, 메인 프로그램은 손자에 대해 직접적인 가시성을 갖지 않습니다. 하위 프로세스를 실행 중입니다. 이제 프로세스가 종료되었습니다.

커널은 하위 프로세스 → 상위 프로세스 관계를 추적합니다. ps -o ppid= -p $pidID가 있는 프로세스의 상위 프로세스에 대한 프로세스 ID를 보기 위해 실행할 수 있습니다 $pid. 커널은 프로세스의 상위 프로세스를 추적하지 않습니다. 또한 상위 프로세스가 종료되면 해당 프로세스는 init(프로세스 번호 1)에 의해 채택되므로 해당 시점부터 해당 상위 프로세스 ID는 1이 됩니다.

추적할 수 있는 다른 상속된 프로세스 속성이 여러 가지 있습니다. 그러나 손자는 이러한 속성 중 하나라도 벗어날 수 있습니다. 손자가 데몬으로 실행되도록 의도된 경우 대화형 세션에 묶여 있지 않고 관련될 위험이 없도록 가능한 한 스스로를 격리하려고(중개자 또는 손자 자체로부터) 시도할 수 있습니다. 이번 회의에서 무슨 일이 일어나고 있는지.

ps -o pgid=현재 프로세스( ) 와 동일한 프로세스 그룹에 속한 프로세스를 찾을 수 있습니다 . 이는 동일한 프로세스 그룹에서 시작된 다른 프로세스를 포착하지만, 반대로 자식 프로세스 setpgid또는 손자 프로세스 호출로 인해 자체 프로세스 그룹에서 실행 중인 경우 손자 프로세스를 놓칩니다 setpgrp(데몬이 수행함).

ps -o sid=현재 프로세스( ) 와 동일한 세션 ID에 있는 프로세스를 찾을 수 있습니다 . 이는 동일한 세션 ID에서 시작된 다른 모든 프로세스를 포착하지만, 반대로 자체 세션에서 실행 중인 경우 setsid하위 프로세스 또는 손자 프로세스 호출로 인해 손자 프로세스를 놓치게 됩니다(데몬이 수행함).

임시 파일을 열고 파일(`fuser "$tmpfile")을 연 프로세스를 찾을 수 있습니다. 이는 이 파일을 연 기본 프로세스 부분에서 시작된 프로세스만 캡처하고 기본 프로세스의 다른 구성 요소가 수행했을 수 있는 작업은 캡처하지 않기 때문에 더 안정적입니다. 그러나 다른 솔루션과 마찬가지로 해당 프로세스 또는 중간 하위 프로세스가 사용하지 않는 파일 설명자를 닫으면 손자 프로세스가 누락되는 반면 데몬 프로세스는 이를 수행합니다.

대부분의 데몬에는 포그라운드에 머물 수 있는 명령줄 옵션이 있습니다. 그런 다음 를 실행할 수 있으며 daemon --foreground & daemon_pid=$!세션 종료 시 데몬이 포착되지 않도록 예방 조치를 취해야 합니다( nohup daemon --foreground </dev/null >daemon.log 2>&1 &이것은 좋은 시작입니다).

답변3

strace스크립트를 사용하여 일부 정보를 얻을 수 있지만 하위 명령이 완료될 때까지 strace가 계속 실행됩니다. 예를 들어,

$ strace -b execve -e trace=none -e signal=none -f my-app
Process 21697 attached             <-- is the () &
[pid 21696] +++ exited with 0 +++  <-- is my-app ending
Process 21698 attached             <-- is the sleep 10
Process 21698 detached
test
Process 21702 attached             <-- is the sleep 5
Process 21702 detached
+++ exited with 0 +++

echo따라서 우리는 서브쉘의 pid를 갖고 있으며, 내장 쉘이라고 가정하여 명령이 그곳에서 실행되므로 추적되지 않습니다. -b execve실행 시간에 분리하고 -f자식을 추적하여 -e아무것도 추적하지 않음으로써 출력을 줄이는 것입니다.

관련 정보