다음 2개의 스크립트가 있습니다.
script1.sh
:
#!/usr/bin/env bash
set -x
set -e
./script2.sh &
pid=$!
max_retry=15
counter=0
until curl --silent --head --fail localhost:8000; do
if ! jobs %1; then
echo "Server quit unexpectedly before reporting successful status"
exit 1
fi
if [[ $counter -eq $max_retry ]]; then
echo "Server never reported healthy status"
kill -INT $pid
wait $pid
exit 1
fi
echo "Server not ready. Sleeping for 1 second"
sleep 1
counter=$((counter + 1))
done
echo "Server responded healthy"
kill -INT $pid
wait $pid
echo "Done"
script2.sh
:
#!/usr/bin/env bash
set -x
set -e
docker run \
-p 8000:80 \
nginxdemos/hello
을 실행할 때 스크립트가 백그라운드에서 실행되어 성공할 때까지 실행한 다음 종료 하도록 ./script1.sh
하고 싶습니다 . 그러나 이것은 일어나지 않았습니다. 26행은 스크립트를 종료하지 않습니다. 대신 + 를 누를 때까지 계속 실행하세요 .script2.sh
curl
script2.sh
SIGINT
kill
script2.sh
Ctrl
C
왜 이런 일이 발생합니까? 하위 프로세스에 신호를 script2.sh
올바르게 종료하고 전파하는 방법은 무엇입니까 ?SIGINT
답변1
낮은 수준의 운영 체제 관점에서 올바른 접근 방식은 PID에 음수 값을 전달하여 kill
프로세스 그룹 ID(PGID)를 지정하는 것입니다.
안타깝게도 그룹 ID로 종료하려는 프로세스가 종료하려는 상위 프로세스와 동일한 그룹에 있는 경우가 많습니다. 단, 상위 그룹을 포함한 전체 그룹이 종료됩니다.
이것은 해킹을 통해서만 해결될 수 있는 어리석은 유닉스 문제이다.
나는 당신과 비슷한 script1.sh
배경을 가지고 있습니다. 나는 명령이 없습니다 . 내가 죽이면 그들은 아직 살아 있습니다.script2.sh
docker
sleep 3600
script2.sh
script2.sh
sleep 3600
script2.sh
:
#!/bin/sh
sleep 3600
에서는 script1.sh
Awk 프로그램을 사용하여 프로세스의 모든 자손을 찾습니다 script2.sh
.
script1.sh
:
#!/bin/sh
./script2.sh &
pid=$!
sleep 1
descendants=$(awk -f descendants.awk $pid)
kill -TERM $pid
for desc in $descendants; do
kill -TERM $desc
done
# wait for script2.sh by pid
wait $pid
echo done
이 내 꺼야 descentants.awk
:
BEGIN {
# symbolic names for "ps -efj" columns
PID=2
PPID=3
root_process = ARGV[1]
while (("ps -efj" | getline) > 0)
parent[$PID] = $PPID
for (child in parent) {
pid = child;
do {
par = parent[pid]
if (par == root_process) {
print child
break
}
pid = par
} while (par != 0 && par != 1)
}
}
이는 출력의 열 2와 3을 기반으로 연관 해시를 구축하여 달성됩니다 ps -efj
. 이 해시는 시스템에 있는 특정 PID의 상위 항목을 제공합니다. 그런 다음 모든 PID를 반복합니다. 각 pid에 대해 친족 사슬을 따라 조상을 추적합니다. 주어진 pid를 갖는 모든 pid를 직접 또는 간접 조상으로 인쇄합니다.
이는 부모가 사망하여 PID 1로 재설정된 자손을 찾지 않습니다(Awk 스크립트가 혈통 데이터를 수집하기 전).
script2.sh
백그라운드 에 두고 종료 하는 경우와 마찬가지로 sleep 3600 &
Awk 스크립트는 sleep
계속 실행되지만 PPID는 1입니다.
즉, 스크립트와 그 하위 항목이 잘 작동한다고 가정합니다. 무엇이든지 자기 뜻대로 죽으면 깨끗하게 죽고 후손이 남지 않도록 조심하느니라. 갑자기 죽이면 우리가 미래 세대를 책임질 것이다.
추신: 저는 GNU Linux에서 작업하고 있습니다. 출력 을 pstree -Tp
. -T
그것은 우리가 하지 않는 또 다른 일입니다. 우리는 스레드에 대해 이야기하지 않습니다. 프로세스를 종료하면 해당 스레드가 스레딩 라이브러리에 의해 처리된다고 가정합니다. 스레드는 실제로 Linux의 프로세스입니다.
예: 이는 출력의 일부입니다 pstree -Tp
.
│ ├─firefox(22690)─┬─Isolated Web Co(22776)
│ │ ├─Isolated Web Co(22880)
│ │ ├─Privileged Cont(22870)
│ │ ├─Socket Process(22748)
│ │ ├─Web Content(22907)
│ │ ├─Web Content(22934)
│ │ ├─Web Content(27810)
│ │ └─WebExtensions(22820)
다음은 스크립트의 출력입니다.
$ awk -f descendants.awk 22690
22820
22880
22907
22776
22870
22934
27810
22748
동일한 8개의 프로세스가 발견되었습니다. 하위 트리 깊이가 1을 초과하는 또 다른 예:
│ ├─gnome-terminal-(6802)───bash(6814)─┬─git(365)───wish(368)─┬─aspell(382)
│ │ │ └─git-diff-index(15474)
│ │ ├─git(26636)───wish(26641)───aspell(26650)
│ │ ├─txr(15717)
│ │ └─vi(933)
$ awk -f descendants.awk 6802
365
26641
368
382
15474
26636
26650
933
15717
6814