Previous Section  < Day Day Up >  Next Section

12.9. Trapping Signals

While your program is running, if you press Ctrl-C or Ctrl-\, the 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.[5] 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 single quotes, those commands will be executed upon receipt of a specified signal. Use the command kill –l to get a list of all signals and the numbers corresponding to them.

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

FORMAT


trap 'command; command' signal


Example 12.59.

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


EXPLANATION

When any of the signals 1 (hangup), 2 (interrupt), or 15 (software termination) arrives, remove all the tmp files and then 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. See Table 12.12 for a list of signal numbers and their corresponding names.[6] Type kill -l to get the output shown in Table 12.12.

[6] For a complete discussion of UNIX signals, see W. Richard Stevens, Advanced Programming in the UNIX Environment (Boston: Addison-Wesley Professional, 1992).

Table 12.12. 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 this command may differ slightly with the operating system.

[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.

12.9.1 Pseudo or Fake Signals

These three fake signals are not real signals, but are generated by the shell to help debug a program. They are treated like real signals by the trap command and defined in the same way. See Table 12.13 for a list of pseudo signals.

Table 12.13. Korn Shell Fake Trap Signals

Signal

What It Does

DEBUG

Executes trap commands after every script command

ERR

Executes trap commands if any command in the script returns a nonzero exit status

0 or EXIT1

Executes trap commands if the shell exits


Signal names such as HUP and INT are normally prefixed with SIG, for example, SIGHUP, SIGINT, and so forth. The Korn 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 Example 12.60.

12.9.2 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 local to functions; that is, they are not known outside the function where they were set.

Example 12.60.

trap 2  or  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.

12.9.3 Ignoring Signals

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

Example 12.61.

trap " " 1 2    or    trap "" HUP INT


EXPLANATION

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

12.9.4 Listing Traps

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

Example 12.62.

(The Script)

     #!/bin/ksh

     # Scriptname: trapping

     # Script to illustrate the trap command and signals

     # Can use the signal numbers or ksh abbreviations seen

     # below. Cannot use SIGINT, SIGQUIT, etc.

1    trap 'print "Ctrl–C will not terminate $PROGRAM."' INT

2    trap 'print "Ctrl–\ will not terminate $PROGRAM."' QUIT

3    trap 'print "Ctrl–Z will not terminate $PROGRAM."' TSTP

4    print "Enter any string after the prompt.\

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

5    while true

     do



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

7         read

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

          then

9              break

          fi

10   done



(The Output)

     $ trapping

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 background 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 line 7).

  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.

Example 12.63.

(The Script)

     $ cat trap.err

     #!/bin/ksh

    # This trap checks for any command that exits with a nonzero

     # status and then prints the message.

1    trap 'print "You gave me a non–integer. Try again. "' ERR

2    typeset –i number     # Assignment to number must be integer

3    while true

     do

4        print –n "Enter an integer. "

5        read –r number 2> /dev/null

6        if (( $? == 0 ))     # Was an integer read in?

         then                 # Was the exit status zero?



     n=$number

9    if grep ZOMBIE /etc/passwd > /dev/null 2>&1

     then

         :

     else

10       print "\$n is $n. So long"

     fi



(The Output)

     $ trap.err

4    Enter an integer. hello

1    You gave me a non–integer. Try again.

4    Enter an integer. good–bye

1    You gave me a non–integer. Try again.

4    Enter an integer. \\\

1    You gave me a non–integer. Try again.

4    Enter an integer. 5

10   $n is 5. So long.

     $ trap.err

4    Enter an integer. 4.5

10   $n is 4. So long.


EXPLANATION

  1. The ERR (fake or pseudo) signal will print the message in double quotes any time a command in the program returns a nonzero exit status, that is, fails.

  2. The typeset command with the –i option creates an integer variable, number, which can only be assigned integers.

  3. The exit status of the true command is always 0; the body of the while loop is entered.

  4. The user is asked to type in an integer.

  5. The read command reads user input and assigns it to the number variable. The number must be an integer; if not, an error message will be sent to /dev/null. The –r option to the read command allows you to enter a negative number (starting with the minus sign).

  6. If the exit status from the read command is 0, a number was entered, and the if statements will be executed.

  7. The break command is executed and the loop exits.

  8. The trap for the fake Korn shell signal ERR is unset.

  9. When grep fails, it returns a nonzero exit status; if we had not unset the ERR trap, the script would have printed You gave me a non-integer. Try again. So long if the grep failed to find ZOMBIE in the /etc/passwd file.

  10. This line is printed if the grep failed. Note that if a floating-point number such as 4.5 is entered, the number is truncated to an integer.

12.9.5 Traps and Functions

If trap is used in a function, the trap and its commands are local to the function.

Example 12.64.

(The Script)

     #!/bin/ksh

1    function trapper {

         print "In trapper"

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

         print "Got here."

         sleep 25

     }

3    while :

     do

         print "In the main script"

4        trapper   # Call the function

5        print "Still in main"

         sleep 5

         print "Bye"

     done

------------------------------------------------------



(The Output)

$ functrap

In the main script

In trapper

Got here.

^CCaught in a trap!

$


EXPLANATION

  1. The function trapper is defined. It contains the trap command.

  2. The trap command will be executed if Ctrl-C is entered. The print command within the trap is executed and the program continues execution. Ctrl-C is entered while the sleep command is running. Normally, the program will continue to run just after the command where it was interrupted (with the exception of the sleep command, which causes the program to abort). The trap has no effect on lines starting after 4.

  3. In the main part of the script, a while loop is started. The colon is a do-nothing command that always returns a zero exit status. The loop will go forever.

  4. Once in the loop, the function trapper is called.

  5. The trap command within the trapper function will have no effect in this part of the program because the trap is local to the function. If the function exits normally (i.e., ^C is not pressed), execution will continue here. The default behavior for ^C will cause the script to abort if the signal is sent here or to any of the lines that follow.

    Previous Section  < Day Day Up >  Next Section