Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!samsung!spool.mu.edu!uwm.edu!linac!att!cbnews!lml From: lml@cbnews.att.com (l.mark.larsen) Newsgroups: comp.unix.shell Subject: Re: Getting HUPed Summary: trapping tips Message-ID: <1991Mar29.224644.5231@cbnews.att.com> Date: 29 Mar 91 22:46:44 GMT References: <53902@mirror.tmc.com> Sender: L. Mark Larsen Followup-To: comp.unix.shell Distribution: na Organization: AT&T Bell Laboratories Lines: 112 In article krs@amdahl.uts.amdahl.com (Kris Stephens [Hail Eris!]) writes: # In article <53902@mirror.tmc.com> kiyun@mirror.UUCP (KiYun Roe) writes: # >In article krs@amdahl.uts.amdahl.com (Kris Stephens [Hail Eris!]) writes: # >>The thing about the trapped command is that you don't need to issue # >>an exit from within the command-series. The sh (or ksh) will simply # >>execute the command on its merry way out. This is only true of the 0 (aka EXIT in ksh) "interrupt" - as KiYun pointed out in his reply. # Okay, it ain't clear to me from reading ksh.1. If I.... # # trap 'echo "signalled"' 0 1 2 3 14 15 # # in a script (not in a function of the script), it *is* clear that 0 # will echo "signalled" and exit. It's not clear to me what will happen # on signals 1 2 3 14 15, though. # # Should this work to (a) echo "signalled" and (b) exit, without recursion: # # trap 'echo "signalled"; exit' 0 1 2 3 14 15 # # where by "without recursion" I mean successive firings on the trap? # What would the exit code be if the trap is taken by execution of an # 'exit 1' in the script? Would it be 0 because the echo was a success? No, it would be 0 because no argument is supplied to the exit. # Should I, instead, do: # # trap 'echo "signalled"' 0 # trap 'echo "signalled"; exit' 1 2 3 14 15 # # to avoid a possible recursion and protect the exit code? This won't protect the exit code either. # # Anyone *really* know? Well, let me give it my best shot... Think of traps as being like signal handlers in C under UNIX(TM). If you don't catch the signal, the default action is to terminate the program. The same is true of a shell script. You can ignore signals in a program. To do the same in a shell script, you set the action to the null string: trap "" 1 2 3 15 # ignore some interrupts Finally, you can call some user-defined signal handler which can do pretty much anything you want. In a shell script, the same is true. (For the remainder of my message, I'll be talking about ksh88e, which is what I use. The principles are generally true with earlier versions of ksh or with the Bourne shell.) I have used traps quite a bit and had occasion to explore their behavior rather thoroughly. First of all, the book states that, if several events ("interrupts") occur at about the same time, they are handled in the following order: DEBUG ERR all true interrupts (in numerical order) EXIT The EXIT trap is called whenever you 'exit' explicitly or the script finishes executing in some fashion. Note that the shell also provides the -e flag which is similar to, but separate from, the ERR trap. This flag takes precedence over the real interrupts and causes an exit to occur, which will trigger any EXIT trap. By the same token, DEBUG is similar to, but different from, the -x flag. With these ideas in mind, it is possible to do many interesting things. One other point about traps and true interrupts (e.g., SIGINT): two or more in a row can cause the trap to be started multiple times (depending on how close together the interrupts are and how long it takes to execute the trap action), so I think it is best to reset the trap first thing to ignore future interrupts: trap 'trap "" 1 2 3 15; rm -f $TMPFILE; exit 1' 1 2 3 15 Finally, I usually prefer to set all my traps at once (whenever the action is the same) but this can cause the EXIT trap to be called twice if a true interrupt occurs. It also would cause the script to always exit with a value of 1. To get around this, I take advantage of the fact that the trap action is expanded at execution time, so I do something like this (note: you must use single quotes (or something equivalent) to protect against the expansion of $RET at the time the trap is set): RET=1 trap 'trap "" 1 2 3 15; rm -f $TMPFILE; trap 0; exit $RET' 0 1 2 3 15 # the script does its thing and at the end or before an explicit call to # exit, I put: RET=0 So, what happens is that the call to 'rm -f $TMPFILE' is made just once, regardless of whether the script terminates normally or not. Also, the script exits with a value indicative of what caused it to terminate. I've noted one funny thing that I think is a bug (inherited from the Bourne shell?): If SIGINT is sent with the traps as noted above, then $? is set to 129 rather than 1 (or even 130). The ksh book states $? is the value of the last command executed and that it is 128 plus the signal number when an interrupt terminated the command. In this case though, the last command executed by the script is 'exit $RET', so I think the value of $? should be 1. If the script terminates due to some other signal (e.g., SIGHUP) the value of $? is indeed 1. Hope this helps... L. Mark Larsen lml@atlas.att.com