Previous Section  < Day Day Up >  Next Section

8.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.[4] 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.

[4] 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 to get a list of all signals. Table 8.5 provides a list of signal numbers and their corresponding names.

Table 8.5. Signal Numbers and Signals[a], [b]

1) HUP

12) SYS

23) POLL

2) INT

13) PIPE

24) XCPU

3) QUIT

14) ALRM

25) XFSZ

4) ILL

15) TERM

26) VTALRM

5) TRAP

16) URG

27) PROF

6) IOT

17) STOP

28) WINCH

7) EMT

18) TSTP

29) LOST

8) FPE

19) CONT

30) USR1

9) KILL

20) CHLD

31) USR2

10) BUS

21) TTIN

 

11) SEGV

22) TTOU

 


[a] The output of the kill command may differ depending on the OS and/or the shell.

[b] 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


Example 8.52.

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


EXPLANATION

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

If an interrupt signal comes in while the script is running, the trap command lets you handle the 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.

8.8.1 Resetting Signals

To reset a signal to its default behavior, the trap command is followed by the signal name or number.

Example 8.53.

trap 2


EXPLANATION

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

Example 8.54.

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, the second trap resets the trap back to its default action, which is to kill the process.

8.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 8.55.

trap " "  1  2


EXPLANATION

Signals 1 and 2 will be ignored by the shell.

8.8.3 Listing Traps

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

Example 8.56.

(The Script)

     #/bin/sh

     # Scriptname: trapping

     # Script to illustrate the trap command and signals

1    trap 'echo "Ctrl–C will not terminate $0."' 2

2    trap 'echo "Ctrl–\ will not terminate $0."' 3

3    echo "Enter any string after the prompt."

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

4    while true

     do

         echo  –n "Go ahead...> "

         read reply

5        if [ "$reply" = stop ]

         then

6            break

         fi

7        done



(The Output)

Enter any string after the prompt.

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

Go ahead...> this is it^C

Ctrl–C will not terminate trapping.

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

Ctrl–\ will not terminate trapping.

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, by default, kills the process and produces a core file.

  3. The user is prompted for input.

  4. The while loop is entered and a prompt, Go ahead...>, is displayed.

  5. The user input is assigned to the reply variable and, if its value matches stop, the loop exits and the program terminates. This is the way we will get out of this program unless it is killed with the kill command.

  6. The break command causes the body of the loop to be exited with control starting after line 7. In this case, the program is at its end.

  7. This is the end of the while loop.

8.8.4 Traps in 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, Ctrl-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 8.57.

(The Script)

     #!/bin/sh

1    trapper () {

        echo "In trapper"

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

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

        sleep 5

    done



(The Output)

In the main script

In trapper

Still in main

^CCaught in a trap!

In the main script

In trapper

Still in main

^CCaught in a trap!

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 signal 2, the interrupt key (^C). If ^C is pressed, the message Caught in a trap! is printed, and the script continues forever.

  3. The main script starts a forever loop.

  4. The function trapper is called.

  5. When the function returns, execution starts here.

8.8.5 Debugging

By using the –n option to the sh command, you can check the sytnax of your scripts without really executing any of the commands. If there is a syntax error in the script, the shell will report the error. If there are no errors, nothing is displayed.

The most commonly used method for debugging scripts is to use the set command with the –x option, or to use the –x option as an argument to the sh command, followed by the script name. See Table 8.6 for a list of debugging options. These options allow an execution trace of your script. Each command from your script is displayed after substitution has been performed, and then the command is executed. When a line from your script is displayed, it is preceded with a plus (+) sign.

Table 8.6. Debugging Options

Command

Option

What It Does

sh –x scriptname

Echo option

Displays each line of script after variable substitutions and before execution

sh –v scriptname

Verbose option

Displays each line of script before execution, just as you typed it

sh –n scriptname

Noexec option

Interprets but does not execute commands

set –x

Turns on echo

Traces execution in a script

set +x

Turns off echo

Turns off tracing


With the verbose option turned on, or by invoking the Bourne shell with the –v option (sh –v scriptname), each line of the script will be displayed just as it was typed in the script, and then executed.

Example 8.58.

(The Script)

     #!/bin/sh

1    # Scriptname: todebug

     name="Joe Blow"

     if  [ "$name" = "Joe Blow" ]

     then

         echo "Hi $name"

     fi

     num=1

     while [ $num -lt 5 ]

     do

          num=`expr $num + 1`

     done

     echo The grand total is $num



(The Command Line and Output)

2    $ sh –x todebug

     + name=Joe Blow

     + [ Joe Blow =  Joe Blow ]

     + echo Hi Joe Blow



     Hi Joe Blow

     num=1

     + [ 1 -lt 5 ]

     + expr 1 + 1

     num=2

     + [ 2 -lt 5 ]

     + expr 2 + 1

     num=3

     + [ 3 -lt 5 ]

     + expr 3 + 1

     num=4

     + [ 4 -lt 5 ]

     + expr 4 + 1

     num=5

     + [ 5 -lt 5 ]

     + echo The grand total is 5

     The grand total is 5


EXPLANATION

  1. The script is called todebug. You can watch the script run with the –x switch turned on. Each iteration of the loop is displayed and the values of variables are printed as they are set and when they change.

  2. The sh command starts the Bourne shell with the –x option. Echoing is turned on. Each line of the script will be displayed to the screen prepended with a plus sign (+). Variable substitution is performed before the line is displayed. The result of the execution of the command appears after the line has been displayed.

    Previous Section  < Day Day Up >  Next Section