die函数
18.4 错误处理
在很多情况下,系统调用可能会失败;例如,尝试打开不存在的文件,或者删除某个仍含有文件的目录,或者
尝试读取没有读权限的文件。在前面的示例中,我们已经用到了die函数,本节将 详细讨论有关错误处理和错
误处理函数的相关内容。这些函数包括die函数、warn函数和eval函数。
die函数用于在命令或文件句柄失败时退出Perl脚本。
warn函数类似于die函数,但它不会退出脚本。
eval函数具有多种用途,但它主要还是用于异常处理。
读者想必还记得短路运算符&&和||,这两个运算符首先会求其左侧操作数的值,然后才会求其右侧操作数的值
。如果&&左侧操作数值为true,则求其右侧的操作数。如果||左侧操作数的值为 false,这才求其右侧的操作
数。
Carp.pm模块。 有很多种退出脚本的途径可供用户选择。Perl 5提供的Carp模块扩展了die和warn的功能。(详
见示例12.10。)
18.4.1 die函数
如果系统调用失败的话,die函数会把字符串打印到STDERR上,并以$!的当前值退出脚本。$!变量中含有errno
的当前值,后者是一个UNIX全局变量,含有一个表示系统错误的数字。只有在系 统调用失败时才会更新errno
的值。当系统调用失败时,会向errno赋予一个数字代码,以表明错误的类型。如果在字符串中省略了换行符,
则会打印出带有行号的消息(参 见/usr/include/sys中的完整列表)。
下面是/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的错误代码不同于UNIX错误代码,因此不能依赖于$!返回的值。有很多Win32扩展都提供了自己的错误函
数,以便为用户提供更有意义的结果。详情可参阅ActiveState中标准Perl库里的 Win32::GetLastError相关文
档。
格式
die(LIST)die LISTdie
示例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
解释
1. chdir调用失败。$!中含有来自errno的错误消息。换行符导致打印了die函数后面的字符串,该字符串中含
有变量$!的值。
示例18.67
(In Script)1 die unless chdir '/plop' ;(Output)1 Died at croak.perl line 4.
解释
1. chdir调用失败。这一次$!并不在die字符串中,打印发生错误的行。
示例18.68
(In Script)1 chdir '/plop' or die "Stopped";(Output)1 Stopped at croak.perl line 4.
解释
1. 本示例的输出内容与前一个示例相同,但它使用的不同的语法。如果chdir调用失败,就执行or右边的die函
数。
warn函数
warn函数(运算符)和die几乎一样,所不同的是前者会让程序继续运行。如果在eval块中调用die函数,则传
递给die的参数字符串将同样赋值给特殊变量$@。在调用die之后,该变量可以作为一个参数传递给warn函数,
其输出将发送到STDERR上(参阅"ecal函数"一节)。
eval函数
eval函数用于处理异常,即捕捉错误。位于eval之后的语句块是作为单独的Perl程序来处理和解析的,但其所
有的变量设置、子例程以及格式定义都将保持到eval执行完毕。
eval函数返回的值是上一个表达式的值。如果出现了编译或运行时错误,或者执行了die语句的话,则会返回未
定义的值,并将特殊变量$@设置为错误消息内容。如果没有发生错误,则$@将是空字符串。
借助eval求Perl表达式的值
示例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: plsh1
print "> "; # Print the prompt2 while(){3 $result=eval ;
# eval evaluates the expression $_4 warn $@ if $@;
# If an error occurs, it will be assigned toprint "$result\n if $result";6 print "> ";
# Print the prompt}(Output)(The Command line)$ plsh2 > hello5 hello2 > bye5 bye2 > 5
+ 45 92 > 8 / 35 2.666666666666672 > 5 / 04 Illegal division by zero at (eval 5) line 3,
line 5.> "Oh I seeCan't find string terminator '"' anywhere before EOF at (eval 6)line 1,
line> exit
解释
1. 本行向用户打印出一个提示信息。该程序类似于小型Perl shell。它能帮助用户在把表达式放进程序之前检
查它的好坏,特别是在不确定Perl会如何处理该表达式时。
2. 进入while循环。每次进入循环时,就从用户处读取一行输入,并赋值给$_。
3. 不带参数的eval将对$_中的表达式求值,并将求值结果赋予$result。
4. 如果eval发现了求值表达式引起的语法错误或系统错误的话,就将返回的错误信息赋值给变量$@。如果没有
发现错误,则把$@赋值为空字符串。
5. 如果对表达式求值成功,打印其结果。
6. 显示提示信息,并再一次进入循环。
使用eval捕捉程序中的错误
示例18.70
(In Script)#!/bin/perlprint "Give me a number.";chop($a=);print "Give me a divisor.";chop
($b=);1 eval{ die unless $answer = $a/$b ; };2 warn $@ ifprintf "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.45Give me a divisor.63 Division of 45.00 by 6.00 is 7.50.4 I'm here now. Good-day!
(Output)Give me a number.5Give me a divisor.02 Illegal division by zero at ./eval.p line 8,
line 2.4 I'm here now. Good-day!
解释
1. eval函数会计算除法($a/$b),并将结果保存到$answer中。请注意,必须首先在eval中使用$answer,该会
一直保留到eval执行结束。
2. 如果一切正常,并且除法运算顺利完成,则忽略这一行。如果发现错误(例如除以0),则将$@变量设置为
系统错误信息,然后通过warn函数将消息打印到STDERR,并恢复程序执行。如果在eval块中调用了die函数,则
程序不退出,而是在退出eval块之后继续执行。
3. 如果运行成功,则打印除法运算的结果。
4. 打印该行内容只是为了说明,程序即使失败了也会继续执行,因为warn函数不会导致脚本退出。
eval函数和here文档
示例18.71
(The Script)#!/bin/perl1 eval<<"EOF";2 chdir "joker" || die "Can't cd: $!\n";3 EOF4 print "The
error message from die:print "Program $0 still in progress.\n";(Output)4 The error message from
die: Can't cd: no such file or directory5 Program ./eval4.p still in progress.
解释
1. here文档类似于一种特殊形式的引用。eval函数获得位于第一个EOF和最后一个EOF之间的所有内容。
2. 如果chdir函数调用失败,则调用die函数,并在here文档的最后一个EOF之后恢复程序。
3. EOF表明here文档到此结束。
4. 将die函数的错误消息保存在变量$@中。
5. 程序继续执行。