multiple bash traps for the same signal

后端 未结 12 795
悲哀的现实
悲哀的现实 2020-12-13 01:47

When I use the trap command in bash, the previous trap for the given signal is replaced.

Is there a way of making more than one trap<

相关标签:
12条回答
  • 2020-12-13 02:39

    I didn't like having to play with these string manipulations which are confusing at the best of times, so I came up with something like this:

    (obviously you can modify it for other signals)

    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
    }
    
    0 讨论(0)
  • 2020-12-13 02:42

    Technically you can't set multiple traps for the same signal, but you can add to an existing trap:

    1. Fetch the existing trap code using trap -p
    2. Add your command, separated by a semicolon or newline
    3. Set the trap to the result of #2

    Here is a bash function that does the above:

    # 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
    

    Example usage:

    trap_add 'echo "in trap DEBUG"' DEBUG
    
    0 讨论(0)
  • 2020-12-13 02:45

    I liked Richard Hansen's answer, but I don't care for embedded functions so an alternate is:

    #===================================================================
    # 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
    }
    
    0 讨论(0)
  • 2020-12-13 02:45

    Here's another option:

    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# 
    
    0 讨论(0)
  • 2020-12-13 02:46

    No

    About the best you could do is run multiple commands from a single trap for a given signal, but you cannot have multiple concurrent traps for a single signal. For example:

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

    The first line sets a trap on signal 2 (SIGINT). The second line prints the current traps — you would have to capture the standard output from this and parse it for the signal you want. Then, you can add your code to what was already there — noting that the prior code will most probably include an 'exit' operation. The third invocation of trap clears the trap on 2/INT. The last one shows that there are no traps outstanding.

    You can also use trap -p INT or trap -p 2 to print the trap for a specific signal.

    0 讨论(0)
  • 2020-12-13 02:49

    I would like to propose my solution of multiple trap functions for simple scripts

    # Executes cleanup functions on exit
    function on_exit {
        for FUNCTION in $(declare -F); do
            if [[ ${FUNCTION} == *"_on_exit" ]]; then
                >&2 echo ${FUNCTION}
                eval ${FUNCTION}
            fi
        done
    }
    trap on_exit EXIT
    
    function remove_fifo_on_exit {
        >&2 echo Removing FIFO...
    }
    
    function stop_daemon_on_exit {
        >&2 echo Stopping daemon...
    }
    
    0 讨论(0)
提交回复
热议问题