[shell] 쉘 스크립트가 종료 될 때 백그라운드 프로세스 / 작업을 어떻게 종료합니까?

최상위 스크립트가 종료 될 때 혼란을 해결하는 방법을 찾고 있습니다.

특히를 사용 set -e하려면 스크립트가 종료되면 백그라운드 프로세스가 종료되기를 바랍니다.



답변

엉망을 정리하기 trap위해 사용할 수 있습니다. 특정 신호가 도착했을 때 실행되는 것들의 목록을 제공 할 수 있습니다.

trap "echo hello" SIGINT

그러나 쉘이 종료되면 무언가를 실행하는 데 사용될 수도 있습니다.

trap "killall background" EXIT

내장되어 있으므로 help trap정보를 제공합니다 (bash와 함께 작동). 백그라운드 작업 만 죽이려면 할 수 있습니다

trap 'kill $(jobs -p)' EXIT

'쉘이 $()즉시 대체되지 않도록 single을 사용 하십시오.


답변

이것은 나를 위해 작동합니다 (댓글 작성자 덕분에 개선되었습니다).

trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
  • kill -- -$$전체 프로세스 그룹에 SIGTERM 을 전송하여 하위 항목도 제거합니다.

  • 신호 지정 EXIT은 사용시 유용합니다 set -e(자세한 내용은 여기 참조 ).


답변

업데이트 : https://stackoverflow.com/a/53714583/302079 는 종료 상태 및 정리 기능을 추가하여이를 개선합니다.

trap "exit" INT TERM
trap "kill 0" EXIT

왜 변환 INT하고 TERM종료해야합니까? 모두 kill 0무한 루프에 들어 가지 않고 트리거해야하기 때문 입니다.

왜 방아쇠 kill 0EXIT? 일반 스크립트 엑시트도 트리거해야하기 kill 0때문입니다.

kill 0? 중첩 된 서브 쉘도 종료해야하기 때문입니다. 전체 프로세스 트리 가 다운됩니다 .


답변

트랩 ‘kill $ (jobs -p)’종료

Johannes의 답변을 약간만 변경하고 jobs -pr을 사용하여 프로세스를 강제 종료하고 목록에 몇 가지 신호를 추가합니다.

trap 'kill $(jobs -pr)' SIGINT SIGTERM EXIT


답변

trap 'kill 0' SIGINT SIGTERM EXIT에 설명 된 솔루션 @ tokland의 대답은 정말 좋은이지만, 최신 배쉬는 segmantation 오류와 충돌 을 사용하는 경우. 이는 v. 4.3부터 Bash가 트랩 재귀를 허용하기 때문에이 경우 무한대로됩니다.

  1. 쉘 공정은 접수에 SIGINT하거나 SIGTERM또는 EXIT;
  2. 셸 자체를 포함하여 그룹의 모든 프로세스로 kill 0전송되는 신호가 갇히고 실행 SIGTERM됩니다.
  3. 1로 이동 🙂

트랩을 수동으로 등록 해제하여이 문제를 해결할 수 있습니다.

trap 'trap - SIGTERM && kill 0' SIGINT SIGTERM EXIT

더 멋진 방법은 수신 된 신호를 인쇄하고 “종료 :”메시지를 피하는 것입니다.

#!/usr/bin/env bash

trap_with_arg() { # from https://stackoverflow.com/a/2183063/804678
  local func="$1"; shift
  for sig in "$@"; do
    trap "$func $sig" "$sig"
  done
}

stop() {
  trap - SIGINT EXIT
  printf '\n%s\n' "recieved $1, killing children"
  kill -s SIGINT 0
}

trap_with_arg 'stop' EXIT SIGINT SIGTERM SIGHUP

{ i=0; while (( ++i )); do sleep 0.5 && echo "a: $i"; done } &
{ i=0; while (( ++i )); do sleep 0.6 && echo "b: $i"; done } &

while true; do read; done

UPD : 추가 된 최소한의 예; stop불필요한 신호를 제거하고 출력에서 ​​”Terminated :”메시지를 숨기는 기능이 향상되었습니다 . Trevor Boyd Smith 에게 제안 해 주셔서 감사 합니다!


답변

안전한 측면에 있기 위해 정리 기능을 정의하고 트랩에서 호출하는 것이 좋습니다.

cleanup() {
        local pids=$(jobs -pr)
        [ -n "$pids" ] && kill $pids
}
trap "cleanup" INT QUIT TERM EXIT [...]

또는 기능을 완전히 피하십시오.

trap '[ -n "$(jobs -pr)" ] && kill $(jobs -pr)' INT QUIT TERM EXIT [...]

왜? 단순히 trap 'kill $(jobs -pr)' [...]하나만 사용 하면 트랩 조건이 신호 될 때 백그라운드 작업이 실행 된다고 가정하기 때문 입니다 . 작업이 없으면 다음과 같은 메시지가 나타납니다.

kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]

jobs -pr비어 있기 때문에 -나는 그 ‘트랩’으로 끝났다.


답변

Linux, BSD 및 MacOS X에서 작동하는 멋진 버전입니다. 먼저 SIGTERM을 보내려고 시도하고 성공하지 못하면 10 초 후에 프로세스를 종료합니다.

KillJobs() {
    for job in $(jobs -p); do
            kill -s SIGTERM $job > /dev/null 2>&1 || (sleep 10 && kill -9 $job > /dev/null 2>&1 &)

    done
}

TrapQuit() {
    # Whatever you need to clean here
    KillJobs
}

trap TrapQuit EXIT

작업에는 손자 프로세스가 포함되지 않습니다.