同一信号的多个bash陷阱
当我在bash中使用“trap”命令时,给定信号的前一个陷阱被replace。
对于同一个信号有没有办法让一个以上的陷阱发生?
编辑:
看来我误解了这个问题。 答案很简单:
handler1 () { do_something; } handler2 () { do_something_else; } handler3 () { handler1; handler2; } trap handler3 SIGNAL1 SIGNAL2 ...
原版的:
只需在命令末尾列出多个信号:
trap function-name SIGNAL1 SIGNAL2 SIGNAL3 ...
您可以使用trap -p
find与特定信号关联的function:
trap -p SIGINT
请注意,即使它们是由相同的function处理,也会分别列出每个信号。
给定一个已知的信号,你可以添加一个额外的信号:
eval "$(trap -p SIGUSR1) SIGUSR2"
即使有相同function正在处理其他附加信号,这也是有效的。 换句话说,假设一个函数已经处理了三个信号 – 你可以通过引用一个已经存在的信号再增加两个信号(其中只有一个在结束引用内部显示)。
如果你使用Bash> = 3.2,你可以这样做来提取给定信号的函数。 请注意,它不完全健壮,因为可能会出现其他单引号。
[[ $(trap -p SIGUSR1) =~ trap\ --\ \'([^\047])\'.* ]] function_name=${BASH_REMATCH[1]}
然后,如果您需要使用函数名称等,则可以重新构build陷阱命令。
从技术上讲,你不能为同一个信号设置多个陷阱,但你可以添加到现有的陷阱:
- 使用
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)上设置陷阱。 第二行打印当前陷阱 – 你将不得不从这个捕获标准输出,并parsing它为你想要的信号。 然后,您可以将代码添加到已经存在的代码中 – 注意到之前的代码很可能会包含“退出”操作。 陷阱的第三次调用将清除2 / INT上的陷阱。 最后一个显示,没有陷阱未完成。
您也可以使用trap -p INT
或trap -p 2
打印特定信号的陷阱。
这是另一个select:
on_exit_acc () { local next="$1" eval "on_exit () { local oldcmd='$(echo "$next" | sed -es/\'/\'\\\\\'\'/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#
我喜欢Richard Hansen的答案,但我不在乎embedded函数,所以替代scheme是:
#=================================================================== # 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 }
我不喜欢玩这些在最好的时候混淆的string操作,所以我想出了这样的东西:
(显然你可以修改其他信号)
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 }