2010-07-26 21 views
35

Quando uso il comando "trap" in bash, il trap precedente per il segnale specificato viene sostituito.più trappole bash per lo stesso segnale

C'è un modo per fare più di un fuoco di trappola per lo stesso segnale?

+0

mi sono imbattuto in un problema simile e si avvicinò con [questo] (http://stackoverflow.com/a/16115145/1449569) –

risposta

18

Edit:

Sembra che ho letto male la domanda. La risposta è semplice:

handler1() { do_something; } 
handler2() { do_something_else; } 
handler3() { handler1; handler2; } 

trap handler3 SIGNAL1 SIGNAL2 ... 

originale:

Basta elencare più segnali alla fine del comando:

trap function-name SIGNAL1 SIGNAL2 SIGNAL3 ... 

È possibile trovare la funzione associata a un particolare segnale utilizzando trap -p:

trap -p SIGINT 

Nota che elenca ciascun segnale separatamente anche se sono gestiti dalla stessa funzione.

è possibile aggiungere un ulteriore segnale dato un una nota in questo modo:

eval "$(trap -p SIGUSR1) SIGUSR2" 

Questo funziona anche se ci sono altri segnali aggiuntivi in ​​fase di elaborazione da parte della stessa funzione. In altre parole, diciamo che una funzione stava già gestendo tre segnali: si potevano aggiungere altri due semplicemente facendo riferimento a uno esistente e aggiungendone altri due (in cui solo uno è mostrato sopra solo all'interno delle virgolette di chiusura).

Se si utilizza Bash> = 3.2, è possibile eseguire un'operazione come questa per estrarre la funzione in base a un segnale. Si noti che non è completamente robusto perché potrebbero apparire altre virgolette singole.

[[ $(trap -p SIGUSR1) =~ trap\ --\ \'([^\047])\'.* ]] 
function_name=${BASH_REMATCH[1]} 

Quindi è possibile ricostruire il comando trap da zero se è necessario utilizzare il nome della funzione, ecc.

+0

ha chiesto per molteplici trappole per lo stesso segnale, non è la stessa trappola per multiple segnali. – Darron

+0

@Darron: Siamo spiacenti, ho letto male la domanda. La risposta alla domanda ** effettiva ** è molto più semplice e l'ho aggiunta in alto. –

+4

stai ancora sparando solo una trappola - che la trappola in questione invoca più funzioni e raggiunge l'effetto è più o meno indiscutibile. L'unica ragione per cui potrebbero esserci motivi di contestazione è che se handler1 è installato per primo, ed è progettato per uscire, quindi handler2 non verrà attivato. Ma c'è ancora solo una azione sparata. (Sei sempre stato in grado di avere una sequenza arbitrariamente complessa di operazioni nell'azione innescata.) –

7

No

Circa il meglio che si possa fare è eseguire più comandi da una singola trap per un dato segnale, ma non è possibile avere più trappole simultanei per un singolo segnale. Ad esempio:

$ trap "rm -f /tmp/xyz; exit 1" 2 
$ trap 
trap -- 'rm -f /tmp/xyz; exit 1' INT 
$ trap 2 
$ trap 
$ 

La prima riga imposta un trap sul segnale 2 (SIGINT). La seconda riga stampa le trap correnti: dovresti catturare l'output standard da questo e analizzarlo per il segnale che desideri. Quindi, puoi aggiungere il tuo codice a ciò che era già lì - notando che il codice precedente probabilmente include un'operazione di "uscita". La terza invocazione di trap cancella la trappola su 2/INT. L'ultimo mostra che non ci sono trappole in sospeso.

È anche possibile utilizzare trap -p INT o trap -p 2 per stampare il trap per un segnale specifico.

36

Tecnicamente non è possibile impostare più trappole per lo stesso segnale, ma è possibile aggiungere a una trappola esistente:

  1. Fetch il codice trappola esistente utilizzando trap -p
  2. Aggiungere il vostro comando, separati da un punto e virgola o di nuova riga
  3. Impostare la trappola per il risultato di # 2

Ecco una funzione bash che fa quanto sopra:

# 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 

Esempio di utilizzo:

trap_add 'echo "in trap DEBUG"' DEBUG 
+1

Questa è più direttamente una risposta a http://stackoverflow.com/q/16115144/754997 –

3

Ecco un'altra opzione:

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 

Usage:

$ on_exit date 
$ on_exit 'echo "Goodbye from '\''`uname`'\''!"' 
$ exit 
exit 
Sat Jan 18 18:31:49 PST 2014 
Goodbye from 'FreeBSD'! 
tap# 
3

mi è piaciuta la risposta di Richard Hansen, ma non mi interessa per Embedded funziona in modo alternato è:

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

Non mi piace dover giocare con queste manipolazioni di stringhe che sono fonte di confusione il più delle volte, quindi mi si avvicinò con qualcosa di simile:

(ovviamente è possibile modificarlo per altri segnali)

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 
} 
Problemi correlati