2010-07-26 9 views
35

Cuando uso el comando "trap" en bash, se reemplaza la trampa anterior para la señal dada.trampas de bash múltiples para la misma señal

¿Hay alguna manera de hacer que más de una trampa dispare para la misma señal?

+0

me encontré con un problema similar y se acercó con [esto] (http://stackoverflow.com/a/16115145/1449569) –

Respuesta

18

Editar:

Parece que leí mal la pregunta. La respuesta es sencilla:

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

trap handler3 SIGNAL1 SIGNAL2 ... 

original:

Basta con enumerar múltiples señales al final del comando:

trap function-name SIGNAL1 SIGNAL2 SIGNAL3 ... 

Puede encontrar la función asociada a una señal en particular el uso de trap -p:

trap -p SIGINT 

Tenga en cuenta que enumera cada señal por separado, incluso si están manejadas por la misma función.

Se puede añadir una señal adicional dado un uno conocido por hacer esto:

eval "$(trap -p SIGUSR1) SIGUSR2" 

Esto funciona incluso si hay otras señales adicionales de ser procesados ​​por la misma función. En otras palabras, digamos que una función ya maneja tres señales: puede agregar dos más simplemente refiriéndose a una existente y agregando dos más (donde solo una se muestra arriba justo dentro de las comillas de cierre).

Si está utilizando Bash> = 3.2, puede hacer algo como esto para extraer la función dada una señal. Tenga en cuenta que no es completamente robusto porque podrían aparecer otras comillas simples.

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

Luego, podría reconstruir su comando trap desde cero si necesita usar el nombre de la función, etc.

+0

pidió múltiples trampas para la misma señal, no la misma trampa para múltiples señales. – Darron

+0

@Darron: Perdón, leí mal la pregunta. La respuesta a la pregunta ** real ** es mucho más simple y la he agregado en la parte superior. –

+4

usted solo está disparando una trampa, que la trampa en cuestión invoca múltiples funciones y logra que el efecto sea más o menos indiscutible. La única razón para pensar que podría haber algún motivo de disputa es que si handler1 se instala primero y está diseñado para salir, no se disparará handler2. Pero todavía hay una sola acción disparada. (Siempre has sido capaz de tener una secuencia arbitrariamente compleja de las operaciones en la acción activada.) –

7

Sin

Acerca de lo mejor que podría hacer es ejecutar varios comandos desde un único trap para una señal dada, pero no se puede tener múltiples trampas concurrentes para una sola señal. Por ejemplo:

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

La primera línea establece una trampa en la señal 2 (SIGINT). La segunda línea imprime las trampas actuales: deberá capturar la salida estándar de esta y analizarla para la señal que desee. Luego, puede agregar su código a lo que ya estaba allí, señalando que el código anterior probablemente incluirá una operación de 'salida'. La tercera invocación de trampa despeja la trampa en 2/INT. El último muestra que no hay trampas pendientes.

También puede usar trap -p INT o trap -p 2 para imprimir la trampa para una señal específica.

36

Técnicamente no se puede establecer múltiples trampas para la misma señal, pero se puede añadir a una trampa existente:

  1. Fetch el código trampa existente utilizando trap -p
  2. Añadir su comando, separados por un punto y coma o de nueva línea
  3. Establecer la trampa con el resultado de # 2

Aquí es una función bash que hace lo anterior:

# 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 

Ejemplo de uso:

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

Esto es más directamente una respuesta a http://stackoverflow.com/q/16115144/754997 –

3

Aquí hay otra opción:

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 

Uso:

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

me ha gustado la respuesta de Richard Hansen, pero no me importa para dispositivos integrados funciones por lo que una alternativa es:

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

que no me gusta tener que jugar con estas manipulaciones de cadenas, que son confusas en el mejor de los casos, por lo que se me ocurrió algo similar:

(obviamente se puede modificar para otras señales)

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 
} 
Cuestiones relacionadas