Perl comes with a whole bunch of cryptically-named built-invariables, which clever Perl programmers exploit to reduce the number oflines of code in their scripts. This article examines some of the morecommonly-used special variable in Perl, with examples and illustrations ofhow they may be used.
When it comes to dealing with errors, there are a number of variables you should know about. The first of them is the $? variable, which stores the error code returned by a call to an external binary, or to the system() function.
#!/usr/bin/perl
# add a user who already exists
`/usr/sbin/useradd root 2>/dev/null`;
# if error code, return it
if ($?)
{
print "Error code ", $? >> 8;
}
Here's the output:
Error code 9
In case you're wondering about the bitwise operation in the program above - the value stored in the $? variable is a 16-bit integer, of which the first 8 bits represent the error code returned by the invoked command.
You can also use the
$? & 127
operation to obtain information on the termination signal of the command, and
$? & 128
operation to get a Boolean value indicating whether or not the program dumped core.
As you may (or may not) know, Perl also allows you to trap errors in a syntax similar to Java's try-catch() blocks, by enclosing your code in an eval() block. In case the code within the eval() block produces an error, Perl stores the error in the $@ system variable without escalating it to the main program, from whence it may be retrieved for exception-handling purposes. The following example illustrates:
#!/usr/bin/perl
# attempt to use a file which does not exist
eval( "use Timezone;" );
# check for error
if ($@ ne "")
{
print "The following error occurred: ", $@;
}
In this case, since the call to use() is within an eval() block, the error returned when Perl is unable to locate the Timezone package will be trapped by the special $@ variable and will not be escalated upwards to the main program. You can then write your own exception-handling routine to inspect $@ and resolve the error appropriately.
Here's the output, with the $@ error-trapping above in action:
The following error occurred: Can't locate Timezone.pm in @INC (@INC contains: /usr/lib/perl5/5.8.0/i386-linux-thread-multi .) at (eval 1) line 1. BEGIN failed--compilation aborted at (eval 1) line 1.
You can also catch error messages returned by die() within an eval() block with the $@ variable - as illustrated below:
#!/usr/bin/perl
# open file
eval( "open(FILE, '/tmp/dummy.txt') or die ('Could not open file');");
# check for error
if ($@ ne "")
{
print "The following error occurred: ", $@;
}
Here's the output:
The following error occurred: Could not open file at (eval 1) line 1.
In the case of Perl functions that use C library calls, you can also access the error returned by the underlying C library with the special $! variable. In order to illustrate, consider the Perl open() function, which uses the C open() call, in a variant of the example above:
#!/usr/bin/perl
# open file
eval( "open(FILE, '/tmp/dummy.txt') or die ('Could not open file');");
# check for error
print "The following error occurred: $!";
Note how, in this case, the error message displayed is the one returned by the C library, not Perl (compare it with the previous example to see the difference):
The following error occurred: No such file or directory