PreviousNext

Using Catch to Trap Errors and Exceptions

Occasionally, you might want to trap some kinds of errors rather than let them terminate an active command. The catch command lets you trap and ignore errors so your script can continue processing. Let us say your script wants to rename a command if it exists. However, it's possible that the command name might not exist when you execute the rename command.

dcecp> rename move move.old
Error: can't rename "move": command doesn't exist
dcecp>

Use catch to invoke the rename command as a script.

dcecp> catch {ren move move.old}
1
dcecp>

The catch command treats its argument as a script and executes it, returning a 0 on successful execution. If an error occurs, it is caught by the catch command which returns a 1.

You can add a second argument to the catch command. This argument is a variable which catch modifies to hold the script's return value (on successful completion) or the error message. The syntax for the catch command is

catch command varName

One use of catch in scripts is to invoke other procedures. You can read the following script fragment as follows: "If the _dcp_create_group procedure returns unsuccessfully (!= 0) then do the _dcp_cleanup_user_create procedure and display the error stored in the msg variable."

if {[ catch {_dcp_create_group $group group_created} msg] != 0 } {
_dcp_cleanup_user_create $element -principal
error $msg
}

Exceptions are a special class of error generated by the break, continue, and return commands. You use the break and continue commands to terminate loops such as while, for and foreach, and you use the return command to terminate a proc or source command.

Resulting exceptions can be hard to handle in procedures where loops exist 'inside' (as part of) a more comprehensive command. For instance, a user-written procedure that searches for specific object types in CDS might invoke foreach as part of a looping activity to test for the occurrence of particular attributes.

If you use the break, continue, or return commands to manage loop execution or to manage some other 'nested' command (like case, or if, for example), the parent command will not be ready to catch the exception. The parent command will abort and issue an error message as usual. However, the error is associated with the parent command and is difficult to track to the looping command where it actually occurred.

If it's necessary to use a continue, break, or return command to terminate a command that has been called by another command, consider using catch to invoke the nested command which, in turn, calls the continue, break, or return command to recover from errors or exceptions. Used this way, the catch command keeps the exception within the looping or nested procedure where it's easier to track down.

foreach s [server catalog] {
if {[catch {server show $s} srv_sh_out] != 0} {
continue
}