2010-07-26 56 views
35

当我在bash中使用“陷阱”命令时,给定信号的先前陷阱被替换。相同信号的多个bash陷阱

对于同一信号有没有办法让多个陷阱失败?

+0

我遇到了类似的问题,并通过[这里](http://stackoverflow.com/a/16115145/1449569) – 2013-05-22 19:08:50

回答

18

编辑:

看来,我误解了问题。答案很简单:

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]} 

然后,如果您需要使用函数名称等,您可以从头重建陷阱命令。

+0

他要求多陷阱相同的信号,不一样的陷阱多想出了信号。 – Darron 2010-07-26 20:13:02

+0

@达隆:对不起,我误解了这个问题。对**实际**问题的答案要简单得多,而且我已将它添加到顶端。 – 2010-07-26 20:56:15

+4

你仍然只是发射一个陷阱 - 这个陷阱引发了多重功能,达到的效果或多或少都是无可争辩的。认为可能有任何争议的理由的唯一原因是,如果handler1首先安装,并且它被设计为退出,那么handler2将不会被解雇。但仍然只有一个行动被解雇。 (你一直可以在触发动作中有一个任意复杂的操作序列。) – 2010-07-26 21:35:45

7

没有

关于你可以做的是从单一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 INTtrap -p 2打印特定信号的陷阱。

36

从技术上讲,你不能为同一个信号设置多个陷阱,但你可以添加到现有的陷阱:

  1. 取现有疏水阀的代码中使用trap -p
  2. 添加您的命令,用分号隔开或换行
  3. 设置陷阱的#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 "[email protected]"; 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 "[email protected]"; 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 
+1

这更直接地回答了http://stackoverflow.com/q/16115144/754997 – 2015-09-17 03:13:26

3

这里的另一种选择:

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# 
3

我喜欢理查德·汉森的答案,但我不喜欢嵌入式所以备用的功能是:

#=================================================================== 
# 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 "[email protected]"; 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 
} 
0

我不喜欢有这些字符串操作它们在最好的时候混乱玩,所以我想出了这样的事情:

(很明显,你可以修改它的其它信号)

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 
}