쉘 포크가 원래보다 오래 살아남는 것을 방지하시겠습니까?

쉘 포크가 원래보다 오래 살아남는 것을 방지하시겠습니까?

다음과 같은 Bash 스크립트가 있는 경우:

function repeat {
    while :; do
        echo repeating; sleep 1
    done
}
repeat &
echo running once

running once한 번 인쇄되지만 repeat포크는 영원히 존재하여 무한히 인쇄됩니다.

repeat이를 생성한 스크립트가 종료된 후에도 계속 실행되지 않도록 하려면 어떻게 해야 합니까 ?

bash -c새 인터프리터를 명시적으로 인스턴스화하면 상위 프로세스가 사라졌기 때문에 강제로 종료될 것이라고 생각했지만 고아 프로세스가 initPID 1에 의해 채택된 것 같습니다.

다른 파일로 이것을 테스트하십시오.

# repeat.bash
while :; do echo repeating; sleep 1; done

# fork.bash
bash -c "./repeat.bash & echo an exiting command"

실행하면 계속해서 백그라운드에서 계속 실행 ./fork.bash됩니다 .repeat.bash

간단하고 게으른 해결책은 다음 줄을 추가하는 것입니다 fork.bash.

pkill repeat.bash

하지만 다른 중요한 프로세스에서 이 이름을 사용하지 않는 것이 좋습니다. 그렇지 않으면 이름도 지워집니다.

  1. 백그라운드 작업을 생성한 스크립트(또는 프로세스)가 종료될 때 종료되어야 하는 분기된 셸에서 백그라운드 작업을 처리하는 더 좋고 수용 가능한 방법이 있는지 궁금합니다.

  2. 모든 프로세스에 대해 동일한 이름을 맹목적으로 사용하는 것보다 더 좋은 방법이 없다면 pkilling네트워크 서버와 같은 것으로 실행되는 중복 작업을 어떻게 처리하여 종료해야 합니까 ?cron스크립트가 git저장소에 있고 코드가 변경 없이 자체 포함되어야 하므로 작업을 피하고 싶습니다 /etc/.

답변1

스크립트가 종료되기 전에 백그라운드 프로세스가 종료됩니다.

trap '[ "$pid" ] && kill "$pid"' EXIT

function repeat {
    while :; do
        echo repeating; sleep 1
    done
}
repeat &
pid=$!
echo running once

어떻게 작동하나요?

  • trap '[ "$pid" ] && kill "$pid"' EXIT

    이것은. 스크립트가 종료되려고 할 때마다 작은따옴표로 묶인 명령이 실행됩니다. 이 명령은 쉘 변수에 pid널이 아닌 값이 지정되었는지 확인합니다. 있는 경우 해당 프로세스와 관련된 프로세스가 pid종료됩니다.

  • pid=$!

    이는 이전 백그라운드 command()의 프로세스 ID를 repeat &쉘 변수에 저장합니다 pid.

개선하다

~처럼패트릭댓글에서 지적했듯이 스크립트가 종료될 가능성이 있습니다.뒤쪽에백그라운드 프로세스가 시작되지만앞으로변수가 pid설정되었습니다. 다음 코드를 사용하여 이 상황을 처리할 수 있습니다.

my_exit() {
    [ "$racing" ] && pid=$!
    [ "$pid" ] && kill "$pid"
}
trap my_exit EXIT

function repeat {
    while :; do
        echo repeating; sleep 1
    done
}

racing=Y
repeat &
pid=$!
racing=

echo running once

답변2

쉘에는 종료 시 명령을 종료하도록 쉘에 지시하는 명령이 tcsh있습니다 .hup

hup mycommand...

tcsh이는 기능을 지원하지 않기 때문에 기능 실행에 도움이 되지 않습니다 .

에서 zsh작업 제어가 활성화되면 모든 백그라운드 작업에 대해 기본적으로 이 작업이 수행됩니다.

$ zsh -c 'set -m; sleep 2 &'; ps
[1] 23672
zsh:1: warning: 1 jobs SIGHUPed

그러나 스크립트에서 작업 제어를 활성화하면 부작용이 발생할 수 있습니다.

bash이 작업을 수행하는 것도 가능하지만 대화형으로만(스크립트에서 -i를 사용하여 호출해도 이 작업을 수행할 수 있음) 쉘에 로그인한 경우에만(!?) 가능합니다. 그리고 이 옵션을 활성화해야 합니다 huponexit. 그래서:

 bash -O huponexit -lic 'sleep 2 &'

하지만 이는 부작용이 많기 때문에 아마도 좋은 생각은 아닐 것입니다.

또 다른 옵션 zsh은 종료 시 실행 중인 알려진 모든 하위 프로세스를 종료하는 것입니다. 어떤 경우에도 손자 프로세스에 대해 쉽게 알 수 없습니다(항상 종료하고 싶지도 않습니다). 연관 배열에서 사용 가능하게 zsh만드세요 :$jobstates

TRAPEXIT() kill -s HUP ${${jobstates[(R)running:*]/#*:/}/%=*/}
trap exit INT HUP TERM

다른 쉘은 하위 프로세스 목록을 공개하지 않지만 ppid를 사용하여 프로세스를 종료할 수 있습니다 $$. 예를 들면 다음과 같습니다.

trap 'pkill -HUP -P "$$"' EXIT INT HUP TERM

관련 정보