쉘 스크립트가 종료 될 때 백그라운드 프로세스 / 작업을 어떻게 종료합니까?
최상위 스크립트가 종료 될 때 혼란을 해결하는 방법을 찾고 있습니다.
특히를 사용 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
업데이트 : https://stackoverflow.com/a/53714583/302079 는 종료 상태와 정리 기능을 추가하여이를 개선합니다.
trap "exit" INT TERM
trap "kill 0" EXIT
왜 변환 INT
하고 TERM
종료해야합니까? kill 0
무한 루프에 들어 가지 않고 모두 트리거해야하기 때문 입니다.
왜 방아쇠 kill 0
에 EXIT
? 일반 스크립트 엑시트도 트리거해야하기 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가 트랩 재귀를 허용하기 때문에이 경우 무한대로됩니다.
- 쉘 공정은 접수에
SIGINT
하거나SIGTERM
또는EXIT
; - 셸 자체를 포함하여 그룹의 모든 프로세스로
kill 0
전송되는 신호가 갇히고 실행SIGTERM
됩니다. - 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: added minimal example; improved stop
function to aviod de-trapping unnecessary signals and to hide "Terminated:" messages from the output. Thanks Trevor Boyd Smith for the suggestions!
To be on the safe side I find it better to define a cleanup function and call it from trap:
cleanup() {
local pids=$(jobs -pr)
[ -n "$pids" ] && kill $pids
}
trap "cleanup" INT QUIT TERM EXIT [...]
or avoiding the function altogether:
trap '[ -n "$(jobs -pr)" ] && kill $(jobs -pr)' INT QUIT TERM EXIT [...]
Why? Because by simply using trap 'kill $(jobs -pr)' [...]
one assumes that there will be background jobs running when the trap condition is signalled. When there are no jobs one will see the following (or similar) message:
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
because jobs -pr
is empty - I ended in that 'trap' (pun intended).
A nice version that works under Linux, BSD and MacOS X. First tries to send SIGTERM, and if it doesn't succeed, kills the process after 10 seconds.
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
Please note that jobs does not include grand children processes.
function cleanup_func {
sleep 0.5
echo cleanup
}
trap "exit \$exit_code" INT TERM
trap "exit_code=\$?; cleanup_func; kill 0" EXIT
# exit 1
# exit 0
Like https://stackoverflow.com/a/22644006/10082476, but with added exit-code
Another option is it to have the script set itself as the process group leader, and trap a killpg on your process group on exit.
So script the loading of the script. Run a killall
(or whatever is available on your OS) command that executes as soon as the script is finished.
jobs -p does not work in all shells if called in a sub-shell, possibly unless its output is redirected into a file but not a pipe. (I assume it was originally intended for interactive use only.)
What about the following:
trap 'while kill %% 2>/dev/null; do jobs > /dev/null; done' INT TERM EXIT [...]
The call to "jobs" is needed with Debian's dash shell, which fails to update the current job ("%%") if it is missing.
I made an adaption of @tokland's answer combined with the knowledge from http://veithen.github.io/2014/11/16/sigterm-propagation.html when I noticed that trap
doesn't trigger if I'm running a foreground process (not backgrounded with &
):
#!/bin/bash
# killable-shell.sh: Kills itself and all children (the whole process group) when killed.
# Adapted from http://stackoverflow.com/a/2173421 and http://veithen.github.io/2014/11/16/sigterm-propagation.html
# Note: Does not work (and cannot work) when the shell itself is killed with SIGKILL, for then the trap is not triggered.
trap "trap - SIGTERM && echo 'Caught SIGTERM, sending SIGTERM to process group' && kill -- -$$" SIGINT SIGTERM EXIT
echo $@
"$@" &
PID=$!
wait $PID
trap - SIGINT SIGTERM EXIT
wait $PID
Example of it working:
$ bash killable-shell.sh sleep 100
sleep 100
^Z
[1] + 31568 suspended bash killable-shell.sh sleep 100
$ ps aux | grep "sleep"
niklas 31568 0.0 0.0 19640 1440 pts/18 T 01:30 0:00 bash killable-shell.sh sleep 100
niklas 31569 0.0 0.0 14404 616 pts/18 T 01:30 0:00 sleep 100
niklas 31605 0.0 0.0 18956 936 pts/18 S+ 01:30 0:00 grep --color=auto sleep
$ bg
[1] + 31568 continued bash killable-shell.sh sleep 100
$ kill 31568
Caught SIGTERM, sending SIGTERM to process group
[1] + 31568 terminated bash killable-shell.sh sleep 100
$ ps aux | grep "sleep"
niklas 31717 0.0 0.0 18956 936 pts/18 S+ 01:31 0:00 grep --color=auto sleep
Just for diversity I will post variation of https://stackoverflow.com/a/2173421/102484 , because that solution leads to message "Terminated" in my environment:
trap 'test -z "$intrap" && export intrap=1 && kill -- -$$' SIGINT SIGTERM EXIT
'IT' 카테고리의 다른 글
배열의 한 속성에서 알파벳 순서로 배열의 객체 정렬 (0) | 2020.05.25 |
---|---|
팬더 기능을 열에 적용하여 여러 개의 새 열을 작성 하시겠습니까? (0) | 2020.05.25 |
MVC의 비즈니스 로직 (0) | 2020.05.25 |
Java SDK를 설치 한 후 Linux에서 어디서 찾을 수 있습니까? (0) | 2020.05.25 |
오늘 자정과 내일 자정의 Java Date 객체를 만드는 방법은 무엇입니까? (0) | 2020.05.25 |