이 질문에서:쉘 스크립트에서 마지막으로 실행된 명령의 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 $pid
ID가 있는 프로세스의 상위 프로세스에 대한 프로세스 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
아무것도 추적하지 않음으로써 출력을 줄이는 것입니다.