동일한 신호에 대한 여러 bash 트랩
bash에서 "trap"명령을 사용하면 주어진 신호에 대한 이전 트랩이 대체됩니다.
동일한 신호에 대해 둘 이상의 트랩 발사 방법이 있습니까?
편집하다:
질문을 잘못 읽은 것 같습니다. 대답은 간단합니다.
handler1 () { do_something; }
handler2 () { do_something_else; }
handler3 () { handler1; handler2; }
trap handler3 SIGNAL1 SIGNAL2 ...
실물:
명령 끝에 여러 신호를 나열하십시오.
trap function-name SIGNAL1 SIGNAL2 SIGNAL3 ...
다음을 사용하여 특정 신호와 관련된 함수를 찾을 수 있습니다 trap -p
.
trap -p SIGINT
동일한 기능으로 처리되는 경우에도 각 신호를 별도로 나열합니다.
다음을 수행하여 알려진 신호에 대해 추가 신호를 추가 할 수 있습니다.
eval "$(trap -p SIGUSR1) SIGUSR2"
이는 동일한 기능에 의해 처리되는 다른 추가 신호가있는 경우에도 작동합니다. 즉, 함수가 이미 세 개의 신호를 처리하고 있다고 가정 해 보겠습니다. 기존 하나를 참조하고 두 개를 더 추가하는 것만으로 두 개를 더 추가 할 수 있습니다 (닫는 따옴표 바로 위에 하나만 표시됨).
Bash> = 3.2를 사용하는 경우 다음과 같이 신호가 주어진 함수를 추출 할 수 있습니다. 다른 작은 따옴표가 나타날 수 있기 때문에 완전히 견고하지는 않습니다.
[[ $(trap -p SIGUSR1) =~ trap\ --\ \'([^\047]*)\'.* ]]
function_name=${BASH_REMATCH[1]}
그런 다음 함수 이름 등을 사용해야하는 경우 처음부터 트랩 명령을 다시 빌드 할 수 있습니다.
기술적으로 동일한 신호에 대해 여러 트랩을 설정할 수 없지만 기존 트랩에 추가 할 수 있습니다.
- 다음을 사용하여 기존 트랩 코드를 가져옵니다.
trap -p
- 세미콜론 또는 줄 바꿈으로 구분하여 명령을 추가하십시오.
- 트랩을 # 2의 결과로 설정
위의 작업을 수행하는 bash 함수는 다음과 같습니다.
# note: printf is used instead of echo to avoid backslash
# processing and to properly handle values that begin with a '-'.
log() { printf '%s\n' "$*"; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$@"; exit 1; }
# appends a command to a trap
#
# - 1st arg: code to add
# - remaining args: names of traps to modify
#
trap_add() {
trap_add_cmd=$1; shift || fatal "${FUNCNAME} usage error"
for trap_add_name in "$@"; do
trap -- "$(
# helper fn to get existing trap command from output
# of trap -p
extract_trap_cmd() { printf '%s\n' "$3"; }
# print existing trap command with newline
eval "extract_trap_cmd $(trap -p "${trap_add_name}")"
# print the new trap command
printf '%s\n' "${trap_add_cmd}"
)" "${trap_add_name}" \
|| fatal "unable to add to trap ${trap_add_name}"
done
}
# set the trace attribute for the above function. this is
# required to modify DEBUG or RETURN traps because functions don't
# inherit them unless the trace attribute is set
declare -f -t trap_add
사용 예 :
trap_add 'echo "in trap DEBUG"' DEBUG
아니
최선의 방법은 trap
주어진 신호에 대해 단일 명령에서 여러 명령을 실행하는 것이지만 단일 신호에 대해 여러 개의 동시 트랩을 가질 수는 없습니다. 예를 들면 :
$ trap "rm -f /tmp/xyz; exit 1" 2
$ trap
trap -- 'rm -f /tmp/xyz; exit 1' INT
$ trap 2
$ trap
$
첫 번째 라인은 신호 2 (SIGINT)에 트랩을 설정합니다. 두 번째 줄은 현재 트랩을 인쇄합니다. 여기에서 표준 출력을 캡처하고 원하는 신호에 대해 구문 분석해야합니다. 그런 다음 이미있는 코드에 코드를 추가 할 수 있습니다. 이전 코드에는 아마도 '종료'작업이 포함될 것입니다. 트랩의 세 번째 호출은 2 / INT의 트랩을 지 웁니다. 마지막은 미해결 된 함정이 없음을 보여줍니다.
당신은 또한 사용할 수 있습니다 trap -p INT
또는 trap -p 2
특정 신호의 트랩을 인쇄 할 수 있습니다.
Richard Hansen의 대답이 마음에 들었지만 임베디드 기능은 신경 쓰지 않으므로 대안은 다음과 같습니다.
#===================================================================
# FUNCTION trap_add ()
#
# Purpose: appends a command to a trap
#
# - 1st arg: code to add
# - remaining args: names of traps to modify
#
# Example: trap_add 'echo "in trap DEBUG"' DEBUG
#
# See: http://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal
#===================================================================
trap_add() {
trap_add_cmd=$1; shift || fatal "${FUNCNAME} usage error"
new_cmd=
for trap_add_name in "$@"; do
# Grab the currently defined trap commands for this trap
existing_cmd=`trap -p "${trap_add_name}" | awk -F"'" '{print $2}'`
# Define default command
[ -z "${existing_cmd}" ] && existing_cmd="echo exiting @ `date`"
# Generate the new command
new_cmd="${existing_cmd};${trap_add_cmd}"
# Assign the test
trap "${new_cmd}" "${trap_add_name}" || \
fatal "unable to add to trap ${trap_add_name}"
done
}
또 다른 옵션이 있습니다.
on_exit_acc () {
local next="$1"
eval "on_exit () {
local oldcmd='$(echo "$next" | sed -e s/\'/\'\\\\\'\'/g)'
local newcmd=\"\$oldcmd; \$1\"
trap -- \"\$newcmd\" 0
on_exit_acc \"\$newcmd\"
}"
}
on_exit_acc true
용법:
$ on_exit date
$ on_exit 'echo "Goodbye from '\''`uname`'\''!"'
$ exit
exit
Sat Jan 18 18:31:49 PST 2014
Goodbye from 'FreeBSD'!
tap#
나는 최선의 시간에 혼란스러워하는 이러한 문자열 조작을 가지고 노는 것을 좋아하지 않았기 때문에 다음과 같은 것을 생각해 냈습니다.
(분명히 다른 신호를 위해 수정할 수 있습니다)
exit_trap_command=""
function cleanup {
eval "$exit_trap_command"
}
trap cleanup EXIT
function add_exit_trap {
local to_add=$1
if [[ -z "$exit_trap_command" ]]
then
exit_trap_command="$to_add"
else
exit_trap_command="$exit_trap_command; $to_add"
fi
}
이 작업을 편리한 방법으로 해결하기 위해 일련의 함수를 작성했습니다.
traplib.sh
#!/bin/bash
# Script can be ONLY included by "source" command.
if [[ -n "$BASH" && (-z "$BASH_LINENO" || ${BASH_LINENO[0]} -gt 0) ]] && (( ! ${#SOURCE_TRAPLIB_SH} )); then
SOURCE_TRAPLIB_SH=1 # including guard
function GetTrapCmdLine()
{
local IFS=$' \t\r\n'
GetTrapCmdLineImpl RETURN_VALUES "$@"
}
function GetTrapCmdLineImpl()
{
local out_var="$1"
shift
# drop return values
eval "$out_var=()"
local IFS
local trap_sig
local stack_var
local stack_arr
local trap_cmdline
local trap_prev_cmdline
local i
i=0
IFS=$' \t\r\n'; for trap_sig in "$@"; do
stack_var="_traplib_stack_${trap_sig}_cmdline"
declare -a "stack_arr=(\"\${$stack_var[@]}\")"
if (( ${#stack_arr[@]} )); then
for trap_cmdline in "${stack_arr[@]}"; do
declare -a "trap_prev_cmdline=(\"\${$out_var[i]}\")"
if [[ -n "$trap_prev_cmdline" ]]; then
eval "$out_var[i]=\"\$trap_cmdline; \$trap_prev_cmdline\"" # the last srored is the first executed
else
eval "$out_var[i]=\"\$trap_cmdline\""
fi
done
else
# use the signal current trap command line
declare -a "trap_cmdline=(`trap -p "$trap_sig"`)"
eval "$out_var[i]=\"\${trap_cmdline[2]}\""
fi
(( i++ ))
done
}
function PushTrap()
{
# drop return values
EXIT_CODES=()
RETURN_VALUES=()
local cmdline="$1"
[[ -z "$cmdline" ]] && return 0 # nothing to push
shift
local IFS
local trap_sig
local stack_var
local stack_arr
local trap_cmdline_size
local prev_cmdline
IFS=$' \t\r\n'; for trap_sig in "$@"; do
stack_var="_traplib_stack_${trap_sig}_cmdline"
declare -a "stack_arr=(\"\${$stack_var[@]}\")"
trap_cmdline_size=${#stack_arr[@]}
if (( trap_cmdline_size )); then
# append to the end is equal to push trap onto stack
eval "$stack_var[trap_cmdline_size]=\"\$cmdline\""
else
# first stack element is always the trap current command line if not empty
declare -a "prev_cmdline=(`trap -p $trap_sig`)"
if (( ${#prev_cmdline[2]} )); then
eval "$stack_var=(\"\${prev_cmdline[2]}\" \"\$cmdline\")"
else
eval "$stack_var=(\"\$cmdline\")"
fi
fi
# update the signal trap command line
GetTrapCmdLine "$trap_sig"
trap "${RETURN_VALUES[0]}" "$trap_sig"
EXIT_CODES[i++]=$?
done
}
function PopTrap()
{
# drop return values
EXIT_CODES=()
RETURN_VALUES=()
local IFS
local trap_sig
local stack_var
local stack_arr
local trap_cmdline_size
local trap_cmd_line
local i
i=0
IFS=$' \t\r\n'; for trap_sig in "$@"; do
stack_var="_traplib_stack_${trap_sig}_cmdline"
declare -a "stack_arr=(\"\${$stack_var[@]}\")"
trap_cmdline_size=${#stack_arr[@]}
if (( trap_cmdline_size )); then
(( trap_cmdline_size-- ))
RETURN_VALUES[i]="${stack_arr[trap_cmdline_size]}"
# unset the end
unset $stack_var[trap_cmdline_size]
(( !trap_cmdline_size )) && unset $stack_var
# update the signal trap command line
if (( trap_cmdline_size )); then
GetTrapCmdLineImpl trap_cmd_line "$trap_sig"
trap "${trap_cmd_line[0]}" "$trap_sig"
else
trap "" "$trap_sig" # just clear the trap
fi
EXIT_CODES[i]=$?
else
# nothing to pop
RETURN_VALUES[i]=""
fi
(( i++ ))
done
}
function PopExecTrap()
{
# drop exit codes
EXIT_CODES=()
local IFS=$' \t\r\n'
PopTrap "$@"
local cmdline
local i
i=0
IFS=$' \t\r\n'; for cmdline in "${RETURN_VALUES[@]}"; do
# execute as function and store exit code
eval "function _traplib_immediate_handler() { $cmdline; }"
_traplib_immediate_handler
EXIT_CODES[i++]=$?
unset _traplib_immediate_handler
done
}
fi
test.sh
#/bin/bash
source ./traplib.sh
function Exit()
{
echo exitting...
exit $@
}
pushd ".." && {
PushTrap "echo popd; popd" EXIT
echo 111 || Exit
PopExecTrap EXIT
}
GetTrapCmdLine EXIT
echo -${RETURN_VALUES[@]}-
pushd ".." && {
PushTrap "echo popd; popd" EXIT
echo 222 && Exit
PopExecTrap EXIT
}
용법
cd ~/test
./test.sh
산출
~ ~/test
111
popd
~/test
--
~ ~/test
222
exitting...
popd
~/test
동일한 트랩에 대해 여러 처리기를 가질 수있는 방법은 없지만 동일한 처리기로 여러 작업을 수행 할 수 있습니다.
동일한 일을하는 다양한 다른 답변에서 내가 싫어하는 한 가지는 현재 트랩 기능을 얻기 위해 문자열 조작을 사용하는 것입니다. 이를 수행하는 두 가지 쉬운 방법이 있습니다. 배열과 인수입니다. 인수가 가장 신뢰할 수 있지만 먼저 배열을 보여 드리겠습니다.
배열
배열을 사용할 때를 trap -p SIGNAL
반환 한다는 사실에 의존 trap -- ??? SIGNAL
하므로의 값이 무엇이든 ???
배열에 3 개의 단어가 더 있습니다.
따라서 다음을 수행 할 수 있습니다.
declare -a trapDecl
trapDecl=($(trap -p SIGNAL))
currentHandler="${trapDecl[@]:2:${#trapDecl[@]} - 3}"
eval "trap -- 'your handler;'${currentHandler} SIGNAL"
그래서 이것을 설명합시다. 먼저 변수 trapDecl
는 배열로 선언됩니다. 함수 내에서이 작업을 수행하면 로컬이기도하므로 편리합니다.
다음으로의 출력을 trap -p SIGNAL
배열에 할당합니다 . 예를 들어, osht (셸에 대한 단위 테스트)를 소싱 한 후이를 실행하고 신호가 EXIT
. 의 출력 trap -p EXIT
것이다 trap -- '_osht_cleanup' EXIT
이렇게, trapDecl
할당은 다음과 같이 치환된다 :
trapDecl=(trap -- '_osht_cleanup' EXIT)
괄호가 있으므로, 통상의 어레이 할당되어 trapDecl
네 요소 배열된다 trap
, --
, '_osht_cleanup'
및 EXIT
.
다음으로 현재 처리기를 추출합니다. 다음 줄에 인라인 될 수 있지만 설명을 위해 먼저 변수에 할당했습니다. 이 줄을 단순화하여 다음을 수행합니다. currentHandler="${array[@]:offset:length}"
, 이것은 Bash가 length
element에서 시작하는 요소를 선택하는 데 사용하는 구문 offset
입니다. 에서 계산을 시작하므로 0
숫자 2
는입니다 '_osht_cleanup'
. 다음 ${#trapDecl[@]}
은 내부 요소의 수이며 trapDecl
예제에서는 4가됩니다. 당신은 당신이 원하지 않는 세 가지 요소가 있기 때문에 3을 빼기 : trap
, --
및 EXIT
. $(...)
산술 확장이 이미 offset
및 length
인수 에 대해 수행되기 때문에 해당 표현식 주위 에 사용할 필요가 없습니다 .
마지막 줄은를 수행 eval
하는데, 이것은 쉘이의 출력에서 인용을 해석하도록 사용됩니다 trap
. 해당 행에서 매개 변수 대체를 수행하면 예제에서 다음과 같이 확장됩니다.
eval "trap -- 'your handler;''_osht_cleanup' EXIT"
중간에있는 큰 따옴표 ( ''
) 로 혼동하지 마십시오 . Bash는 두 개의 따옴표 문자열이 서로 옆에 있으면 단순히 연결합니다. 예를 들어, Bash '1'"2"'3''4'
에 1234
의해 확장됩니다 . 또는, 더 재미있는 예를 제공하기 위해, 1" "2
같은 것입니다 "1 2"
. 따라서 eval은 해당 문자열을 가져와 평가합니다. 이는 다음을 실행하는 것과 같습니다.
trap -- 'your handler;''_osht_cleanup' EXIT
그리고는, 제대로 인용 사이에 모든 것을 돌려 처리 할 --
및 EXIT
단일 매개 변수로.
더 복잡한 예제를 제공하기 위해 osht 핸들러 앞에 디렉토리 정리를 추가하고 있으므로 EXIT
이제 신호에 다음이 포함됩니다.
trap -- 'rm -fr '\''/var/folders/7d/qthcbjz950775d6vn927lxwh0000gn/T/tmp.CmOubiwq'\'';_osht_cleanup' EXIT
에 할당 trapDecl
하면 핸들러의 공백으로 인해 크기가 6이됩니다. 즉, 단일 요소가 아닌 'rm
하나의 요소이므로 -fr
이기도 'rm -fr ...'
합니다.
그러나 currentHandler
세 가지 요소 (6-3 = 3)를 모두 가져 오면 따옴표 eval
가 실행될 때 작동 합니다.
인수
인수는 모든 배열 처리 부분을 건너 뛰고 eval
인용을 올바르게하기 위해 앞에 사용 합니다. 단점은 bash에서 위치 인수를 대체한다는 것이므로 이것은 함수에서 가장 잘 수행됩니다. 이것은 코드입니다.
eval "set -- $(trap -p SIGNAL)"
trap -- "your handler${3:+;}${3}" SIGNAL
첫 번째 줄은 위치 인수를의 출력으로 설정합니다 trap -p SIGNAL
. 배열 섹션에서 예제를 사용 $1
것 trap
, $2
할 것이다 --
, $3
없을 것이다 _osht_cleanup
(! 따옴표), 그리고 $4
될 것입니다 EXIT
.
다음 줄은 ${3:+;}
. ${X:+Y}
구문 수단 "출력 Y
변수 경우 X
해제 또는 널" . 따라서 ;
if $3
가 설정되어 있거나 그렇지 않으면 아무것도 확장 되지 않습니다 (에 대한 이전 처리기가없는 경우 SIGNAL
).
참조 URL : https://stackoverflow.com/questions/3338030/multiple-bash-traps-for-the-same-signal
'IT이야기' 카테고리의 다른 글
쿼리 중 MySQL 서버와의 연결이 끊어졌습니다. (0) | 2021.04.10 |
---|---|
PHP에서 강제로 메모리 해제 (0) | 2021.04.10 |
matcher의 그룹 방법을 사용할 때 "일치하지 않음" (0) | 2021.04.10 |
잘못된 지연 초기화 (0) | 2021.04.10 |
Xcode가 내 앱을 컴파일하지만 시뮬레이터에서 실행할 수 없습니다. (0) | 2021.04.09 |