Previous Page Next Page

18.4. Error Handling

There are a number of occasions when a system call can fail; for example, when you try to open a file that doesn't exist or remove a directory when it still contains files or when you try to read from a file for which you do not have read permission. Although we have used the die function in earlier examples, now we will go into more detail about error handling and functions you can use to handle errors. The functions are the die function, the warn function, and the eval function.

You may remember that the short-circuit operators, && and ||, evaluate the operands on the left and then evaluate the operands on the right. If the operand to the left of the && is true, the right-hand side is evaluated. If the operand to the left of the || is false, the right-hand side is evaluated.

The Carp.pm Module

There are many ways to die. Perl 5's Carp module extends the functionality of die and warn. (See Example 12.10 on page 384.)

18.4.1. The die Function

If a system call fails, the die function prints a string to STDERR and exits with the current value of $!. The $! variable yields the current value of errno, the UNIX global variable containing a number indicating a system error. The only time that errno is updated is when a system call fails. When a system call fails, a code number is assigned to errno to indicate the type of error. If the newline is omitted in the string, the message is printed with its line number. (See /usr/include/sys for a complete list.)

Here is an example from /usr/include/sys/errno.h:

#define EPERM     1   /* Not owner */
#define ENOENT    2   /* No such file or directory */
#define ESRCH     3   /* No such process */
#define EINTR     4   /* Interrupted system call */
#define EIO       5   /* I/O error */
...

Win32 error codes differ from UNIX error codes, making it impossible to rely on the value returned in $!. There are a number of Win32 extensions that provide their own error functions to give more meaningful results. See the documentation for Win32::GetLastError in the standard Perl library included with ActiveState.

Format

die(LIST)
die LIST
die

Example 18.66.

(In Script)
1   die "Can't cd to junk: $!\n" unless chdir "/usr/bin/junk";

(Output)
1   Can't cd to junk: No such file or directory

Explanation

  1. The chdir failed. The $! contains the error message from errno. The newline causes the string after the die function to be printed with the value of the $! variable.


Example 18.67.

(In Script)
1   die unless chdir '/plop' ;

(Output)
1   Died at croak.perl line 4.

Explanation

  1. The chdir function failed. This time the $! was not included in the die string. The line where the error took place is printed.

Example 18.68.

(In Script)
1   chdir '/plop' or die "Stopped";

(Output)
1   Stopped at croak.perl line 4.

Explanation

  1. This example produces the same output as the previous example but using a different syntax. If chdir fails, the die function to the right of or is executed.

18.4.2. The warn Function

The warn function (operator) is just like the die function except that the program continues to run. If the die function is called in an eval block, the argument string given to die will be assigned to the special variable $@. After a die, this variable can be passed as an argument to warn and the output sent to STDERR. (See "The eval Function".)

18.4.3. The eval Function

The eval function is used for exception handling; that is, catching errors. The block following eval is treated and parsed like a separate Perl program, except that all variable settings and subroutine and format definitions remain after eval is finished.

The value returned from the eval function is that of the last expression evaluated. If there is a compile or runtime error or the die statement is executed, an undefined value is returned, and a special variable, $@, is set to the error message. If there is no error, $@ is a null string.

Evaluating Perl Expressions with eval
Example 18.69.

(The Script)
    #!/bin/perl
    # The eval function will evaluate each line you type
    # and return the result. It's as though you are
    # running a little independent Perl script.
    # Script name: plsh

1   print "> ";        # Print the prompt
2   while(<STDIN>){
3       $result=eval ;  # eval evaluates the expression $_
4       warn $@ if $@;  # If an error occurs, it will be assigned to $@
5       print "$result\n if $result";
6       print "> "; # Print the prompt
    }
(Output)
(The Command line)
    $ plsh
2   > hello
5   hello
2   > bye
5   bye
2   > 5 + 4
5   9
2   > 8 / 3
5   2.66666666666667
2   > 5 / 0
4   Illegal division by zero at (eval 5) line 3, <STDIN> line 5.
    > "Oh I see
    Can't find string terminator '"' anywhere before EOF at (eval 6)
       line 1,  <STDIN> line
    > exit

					  

Explanation

  1. This line prints a prompt for the user. This program is like a little Perl shell. It can help you in evaluating an expression before putting it in a program, especially if you're not sure how Perl will handle it.

  2. The while loop is entered. Each time the loop is entered, it will read a line of input from the user and assign it to $_.

  3. The eval function, without an argument, will evaluate the expression in $_ and assign the result of the evaluation to $result.

  4. If the eval finds a syntax error or a system error results from the evaluation of the expression, the error message returned will be assigned to the $@ variable. If there is no error, the $@ variable is assigned a null string.

  5. If the expression was successfully evaluated, the result will be printed.

  6. The prompt is displayed and the loop reentered.

Using eval to Catch Errors in a Program
Example 18.70.

(In Script)
    #!/bin/perl
    print "Give me a number.";
    chop($a=<STDIN>);
    print "Give me a divisor.";
    chop($b=<STDIN>);
1   eval{ die unless $answer = $a/$b ; };
2   warn $@ if $@;
3   printf "Division of %.2f by %.2f is %.2f.\n",$a,$b,
           $answer if $answer ;
4   print "I'm here now. Good-day!\n";

(Output)
    Give me a number.45
    Give me a divisor.6
3   Division of 45.00 by 6.00 is 7.50.
4   I'm here now. Good-day!

(Output)
    Give me a number.5
    Give me a divisor.0
2   Illegal division by zero at ./eval.p line 8, <STDIN> line 2.
4   I'm here now. Good-day!

Explanation

  1. The eval function will evaluate the division ($a/$b) and store the result in $answer. Note that $answer is first used inside the eval function. It remains after eval is finished.

  2. If all went well, and the division was completed, this line is ignored. If there was an error (e.g., division by zero), the $@ variable is set to the system error. The warn function then prints the message to STDERR, and the program resumes. If the die function is called in an eval block, the program does not exit but continues execution after the eval block exits.

  3. The result of the division is printed, if successful.

  4. This line is printed just to show you that the program continued execution even after a failure, since the warn function does not cause the script to exit.

The eval Function and the here document
Example 18.71.

(The Script)
    #!/bin/perl
1   eval<<"EOF";
2       chdir "joker" || die "Can't cd: $!\n";
3   EOF
4   print "The error message from die: $@";
5   print "Program $0 still in progress.\n";

(Output)
4   The error message from die: Can't cd: no such file or directory
5   Program ./eval4.p still in progress.

Explanation

  1. The here document is like a special form of quoting. The eval function will get everything between the first EOF and the terminating EOF.

  2. If the chdir function fails, the die function is called, and the program resumes after the last EOF of the here document.

  3. EOF terminates the here document.

  4. The error message from the die function is stored in the $@ variable.

  5. The program continues.

Previous Page Next Page