Previous Section  < Day Day Up >  Next Section

14.8. Trapping Signals

While your program is running, if you press Ctrl-C or Ctrl-\, your program terminates as soon as the signal arrives. There are times when you would rather not have the program terminate immediately after the signal arrives. You could arrange to ignore the signal and keep running or perform some sort of cleanup operation before actually exiting the script. The trap command allows you to control the way a program behaves when it receives a signal.

A signal is defined as an asynchronous message that consists of a number that can be sent from one process to another, or by the operating system to a process if certain keys are pressed or if something exceptional happens.[6] The trap command tells the shell to terminate the command currently in execution upon the receipt of a signal. If the trap command is followed by commands within quotes, the command string will be executed upon receipt of a specified signal. The shell reads the command string twice, once when the trap is set, and again when the signal arrives. If the command string is surrounded by double quotes, all variable and command substitution will be performed when the trap is set the first time. If single quotes enclose the command string, variable and command substitution do not take place until the signal is detected and the trap is executed.

[6] Morris I. Bolsky and David G. Korn, The New KornShell Command and Programming Language (Englewood Cliffs, NJ: Prentice Hall PTR, 1995), p. 327.

Use the command kill –l or trap –l to get a list of all signals. Table 14.6 provides a list of signal numbers and their corresponding names. The most commonly used signals for trap are 1) SIGHUP (hangup), 2) SIGINT (interrupt), 3) SIGQUIT (quit), and 4) SIGTERM (exit).

Table 14.6. Signal Numbers and Signals[a]

1) SIGHUP

9) SIGKILL

17) SIGCHLD

25) SIGXFSZ

2) SIGINT

10) SIGUSR1

18) SIGCONT

26) SIGVTALRM

3) SIGQUIT

11) SIGSEGV

19) SIGSTOP

27) SIGPROF

4) SIGILL

12) SIGUSR2

20) SIGTSTP

28) SIGWINCH

5) SIGTRAP

13) SIGPIPE

21) SIGTTIN

29) SIGIO

6) SIGABRT

14) SIGALRM

22) SIGTTOU

30) SIGPWR

7) SIGBUS

15) SIGTERM

23) SIGURG

 

8) SIGFPE

16) SIGSTKFLT

24) SIGXCPU

 


[a] For a complete list of UNIX signals and their meanings, go to www.cybermagician.co.uk/technet/unixsignals.htm. For Linux signals, go to www.comptechdoc.org/os/linux/programming/linux_pgsignals.html.

FORMAT


trap 'command; command' signal-number

trap 'command; command' signal-name


Example 14.61.

trap 'rm tmp*; exit 1'  0 1 2 15

trap 'rm tmp*; exit 1'  EXIT HUP INT TERM


EXPLANATION

When any of the signals 1 (hangup), 2 (interrupt), or 15 (software termination) arrives, remove all the tmp files and exit.

If an interrupt comes in while the script is running, the trap command lets you handle the interrupt signal in several ways. You can let the signal behave normally (default), ignore the signal, or create a handler function to be called when the signal arrives.

Signal names such as HUP and INT are normally prefixed with SIG, for example, SIGHUP, SIGINT, and so forth.[7] The bash shell allows you to use symbolic names for the signals, which are the signal names without the SIG prefix, or you can use the numeric value for the signal. See Table 14.6. A pseudo signal name EXIT, or the number 0, will cause the trap to be executed when the shell exits.

[7] SIGKILL, number 9, often called a "sure kill," is not trappable.

14.8.1 Resetting Signals

To reset a signal to its default behavior, the trap command is followed by the signal name or number. Traps set in functions are recognized by the shell that invoked the function, once the function has been called. Any traps set outside the function are also recognized with the function.

Example 14.62.

trap INT


EXPLANATION

Resets the default action for signal 2, SIGINT. The default action is to kill the process when the interrupt key (Ctrl-C) is pressed.

Example 14.63.

trap 2


EXPLANATION

Resets the default action for signal 2, SIGINT, which is used to kill a process (i.e., Ctrl-C).

Example 14.64.

trap 'trap 2' 2


EXPLANATION

Sets the default action for signal 2 (SIGINT) to execute the command string within quotes when the signal arrives. The user must press Ctrl-C twice to terminate the program. The first trap catches the signal, and the second trap resets the trap back to its default action, which is to kill the process.

14.8.2 Ignoring Signals

If the trap command is followed by a pair of empty quotes, the signals listed will be ignored by the process.

Example 14.65.

trap " " 1 2  or    trap "" HUP INT


EXPLANATION

Signals 1 (SIGHUP) and 2 (SIGINT) will be ignored by the shell process.

14.8.3 Listing Traps

To list all traps and the commands assigned to them, type trap.

Example 14.66.

(At the command line)

1   $ trap 'echo "Caught ya!; exit"' 2

2   $ trap

    trap -- 'echo "Caught ya!; exit 1"' SIGINT

3   $ trap -


EXPLANATION

  1. The trap command is set to exit on signal 2 (Ctrl-C).

  2. The trap command without an argument lists all set traps.

  3. If the argument is a dash, all signals are reset to their original values, that is, whatever they were when the shell started up.

Example 14.67.

(The Script)

    #!/bin/bash

    # Scriptname: trapping

    # Script to illustrate the trap command and signals

    # Can use the signal numbers or bash abbreviations seen

    # below. Cannot use SIGINT, SIGQUIT, etc.

1   trap 'echo "Ctrl-C will not terminate $0."'  INT

2   trap 'echo "Ctrl-\\ will not terminate $0."'  QUIT

3   trap 'echo "Ctrl-Z will not terminate $0."'  TSTP

4   echo  "Enter any string after the prompt.

    When you are ready to exit, type \"stop\"."

5   while true

    do

6       echo –n "Go ahead...> "

7       read

8       if [[ $REPLY == [Ss]top ]]

        then

9           break

        fi

10   done



(The Output)

4   Enter any string after the prompt.

    When you are ready to exit, type "stop".

6   Go ahead...> this is it^C

1   Ctrl-C will not terminate trapping.

6   Go ahead...> this is it again^Z

3   Ctrl-Z will not terminate trapping.

6   Go ahead...> this is never it|^\

2   Ctrl-\\ will not terminate trapping.

6   Go ahead...> stop

    $


EXPLANATION

  1. The first trap catches the INT signal, Ctrl-C. If Ctrl-C is pressed while the program is running, the command enclosed in quotes will be executed. Instead of aborting, the program will print Ctrl-C will not terminate trapping and continue to prompt the user for input.

  2. The second trap command will be executed when the user presses Ctrl-\ , the QUIT signal. The string Ctrl-\\ will not terminate trapping will be displayed and the program will continue to run. This signal, SIGQUIT by default, kills the process and produces a core file.

  3. The third trap command will be executed when the user presses Ctrl-Z, the TSTP signal. The string Ctrl-Z will not terminate trapping will be displayed, and the program will continue to run. This signal normally causes the program to be suspended in the back ground if job control is implemented.

  4. The user is prompted for input.

  5. The while loop is entered.

  6. The string Go ahead...> is printed and the program waits for input (see read on the next line).

  7. The read command assigns user input to the built-in REPLY variable.

  8. If the value of REPLY matches Stop or stop, the break command causes the loop to exit and the program will terminate. Entering Stop or stop is the only way we will get out of this program unless it is killed with the kill command.

  9. The break command causes the body of the loop to be exited.

  10. The done keyword marks the end of the loop.

14.8.4 Traps and Functions

If you use a trap to handle a signal in a function, it will affect the entire script, once the function is called. The trap is global to the script. In the following example, the trap is set to ignore the interrupt key, ^C. This script had to be killed with the kill command to stop the looping. It demonstrates potential undesirable side effects when using traps in functions.

Example 14.68.

(The Script)

    #!/bin/bash

1   function trapper () {

        echo "In trapper"

2       trap 'echo "Caught in a trap!"' INT

        # Once set, this trap affects the entire script. Anytime

        # ^C is entered, the script will ignore it.

    }

3   while :

    do

        echo "In the main script"

4       trapper

5       echo "Still in main"

6       echo "The pid is $$"

        sleep 5

7   done



(The Output)

In the main script

In trapper

Still in main

The pid is 4267

Caught in a trap!      # User presses ^C

In the main script

In trapper

Still in main

The pid is 4267

Caught in a trap!      # User just pressed Ctrl-C

In the main script


EXPLANATION

  1. The trapper function is defined. All variables and traps set in the function are global to the script.

  2. The trap command will ignore INT, signal 2, the interrupt key (^C). If ^C is pressed, the message Caught in a trap! is printed, and the script continues forever. The script can be killed with the kill command or Ctrl-\.

  3. The main script starts a forever loop.

  4. The function trapper is called.

  5. When the function returns, execution starts here.

  6. The PID will be displayed. Later you can use this number to kill the process from another terminal. For example, if the PID is 4267, the kill 4267 will terminate this process.

  7. The program pauses (sleeps) for 5 seconds.

    Previous Section  < Day Day Up >  Next Section