2010-07-26 94 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 
}