Bash


Using "trap" to react to signals and system events All Versions

0.99
1.01
2.0
3.0
3.1
3.2
4.0
4.1
4.2
4.3
4.4

This draft deletes the entire topic.

Introduction

Introduction

expand all collapse all

Examples

  • 17

    You can use the trap command to "trap" signals; this is the shell equivalent of the signal() or sigaction() call in C and most other programming languages to catch signals.

    One of the most common uses of trap is to clean up temporary files on both an expected and unexpected exit.

    Unfortunately not enough shell scripts do this :-(

    #!/bin/sh
    
    # Make a cleanup function
    cleanup() {
      rm --force -- "${tmp}"
    }
    
    # Trap the special "EXIT" group, which is always run when the shell exits.
    trap cleanup EXIT
    
    # Create a temporary file
    tmp="$(mktemp -p /tmp tmpfileXXXXXXX)"
    
    echo "Hello, world!" >> "${tmp}"
    
    # No rm -f "$tmp" needed. The advantage of using EXIT is that it still works
    # even if there was an error or if you used exit.
    
  • 11

    The trap is reset for subshells, so the sleep will still act on the SIGINT signal sent by ^C (usually by quitting), but the parent process (i.e. the shell script) won't.

    #!/bin/sh
    
    # Run a command on signal 2 (SIGINT, which is what ^C sends)
    sigint() {
        echo "Killed subshell!"
    }
    trap sigint INT
    
    # Or use the no-op command for no output
    #trap : INT
    
    # This will be killed on the first ^C
    echo "Sleeping..."
    sleep 500
    
    echo "Sleeping..."
    sleep 500
    

    And a variant which still allows you to quit the main program by pressing ^C twice in a second:

    last=0
    allow_quit() {
        [ $(date +%s) -lt $(( $last + 1 )) ] && exit
        echo "Press ^C twice in a row to quit"
        last=$(date +%s)
    }
    trap allow_quit INT
    
  • 8

    Have you ever forgotten to add a trap to clean up a temporary file or do other work at exit?

    Have you ever set one trap which canceled another?

    This code makes it easy to add things to be done on exit one item at a time, rather than having one large trap statement somewhere in your code, which may be easy to forget.

    # on_exit and add_on_exit
    # Usage:
    #   add_on_exit rm -f /tmp/foo
    #   add_on_exit echo "I am exiting"
    #   tempfile=$(mktemp)
    #   add_on_exit rm -f "$tempfile"
    # Based on http://www.linuxjournal.com/content/use-bash-trap-statement-cleanup-temporary-files
    function on_exit()
    {
        for i in "${on_exit_items[@]}"
        do
            eval $i
        done
    }
    function add_on_exit()
    {
        local n=${#on_exit_items[*]}
        on_exit_items[$n]="$*"
        if [[ $n -eq 0 ]]; then
            trap on_exit EXIT
        fi
    }
    
Please consider making a request to improve this example.

Syntax

  • Run action on a list of signals:
    $ trap [action signals...]
    $ trap ls INT TERM

  • Reset SIGINT and SIGTERM to the default values:
    $ trap number [signals...]
    $ trap 0 INT TERM

  • Lists currently installed traps:
    $ trap

Parameters

Parameters

Remarks

The trap utility is a special shell built-in. It's defined in POSIX, but bash adds some useful extensions as well.

Examples that are POSIX-compatible start with #!/bin/sh, and examples that start with #!/bin/bash use a bash extension.

The signals can either be a signal number, a signal name (without the SIG prefix), or the special keyword EXIT.

Those guaranteed by POSIX are:

NumberNameNotes
0EXITAlways run on shell exit, regardless of exit code
1SIGHUP
2SIGINTThis is what ^C sends
3SIGQUIT
6SIGABRT
9SIGKILL
14SIGALRM
15SIGTERMThis is what kill sends by default
Still have a question about Using "trap" to react to signals and system events? Ask Question

Topic Outline