当前位置: 首页 > 文档资料 > Perl 编程第三版 >

第二十八章 特殊名字

优质
小牛编辑
117浏览
2023-12-01

本章是关于那些对 Perl 有特殊含义的变量的。大多数这些变量都有合理的可记忆性,或者模拟某一种(或两种) shell 的变量。但是如果你想把长变量名当作同义词来用,只需要在你的程序顶部说:

use English;

这样就在当前包里把所有短名字作成长名字的别名。这些变量中有一些甚至还有中间名字,通常是
从 awk 借来的。大多数人最终都使用短名字,至少那些常用的变量是这样的。在本书全部内容中,
我们统一使用短名字,不过也经常提到长名字(在圆括弧里)这样你就可以很容易地在本章中找到
它们。

这些变量的语意可能相当神奇。(要创造自己的神奇,参阅第十四章,捆绑变量。)有少数几个
变量是只读的。如果你试图给它们赋值,那么会抛出一个例外。

在随后的内容里,我们将先提供一个 Perl 赋予了特殊含义的变量和函数的简明列表,按照类型
分组,这样你就可以查找那些你不太能确定正确名字的变量。然后我们将按照它们正确名字(或者
它们的不那么正确的名字)的字母顺序解释所有这些变量。

*按照类型分组的特殊名字

我们这里用的“类型”这个词的含义比较宽松——本节在这里实际上更多地是按照范围来对变量
分组,也就是说,它们在哪里是可见的。

**正则表达式特殊变量

下面的与模式匹配相关的特殊变量在整个发生模式匹配的动态范围内都可见(除了 $* 之外,它现
在是废弃了的)。换句话说,它们的行为就好象它们是用 local 声明的一样,这样你就不用自己
那样定义它们了。参阅第五章,模式匹配。

$*
$digits
@+ (@LAST_MATCH_END)
@- (@LAST_MATCH_START)
$+ ($LAST_PAREN_MATCH)
$^R ($LAST_REGEXP_CODE_RESULT)
$& ($MATCH)
$' ($POSTMATCH)
$` ($PREMATCH)

**每个文件句柄的相关变量

这些特殊变量从不需要在 local 里提到,因为它们总是指向一些属于当前选出的输出文件句柄的
数值 —— 每个文件句柄保存它自己的数值集。但你 select 另外一个文件句柄时,老文件句柄
保存这些变量原来的数值,而这些变量现在反映的是这个新文件句柄的数值。又见第三十二章,
标准模块,里的 FileHandle? 模块。

$| ($AUTOFLUSH, $OUTPUT_AUOTFLUSH)
$- ($FORMAT_LINES_LEFT)
$= ($FORMAT_LINES_PER_PAGE)
$~ ($FORMAT_NAME)
$% ($FORMAT_PAGE_NUMBER)
$^ ($FORMAT_TOP_NAME)

**每个包里的特殊变量

这些特殊变量在每个包里分开存在。你没必要把它们局部化,因为 sort 在 $a 和 $b 上自动做
这些事情,并且其他的变量最好是放在那里别动(尽管如果你 use strict 的话,你可能需要用
out 声明它们)。

$a
$b
@EXPORT
@EXPORT_OK
%EXPORT_TAGS
%fields
@ISA
%OVERLOAD
$VERSION

**程序范围的特殊变量

这些变量在所有意义上都完全是全局的——也就是它们在每个包里的含义都是一样的,因为如果你
不给他们加任何修饰的话,那么它们全部被强制进入到 main 包中(除了 @F 以外,它在 main
里是特殊的,但并不强制)。如果你想用这些变量之一的临时拷贝,那么你必须在当前动态范围里
把它局部化。

%ENV $< ($UID, $REAL_USER_ID)
%INC $> ($EUID, $EFFECTIVE_USER_ID)
...(略)

**每个包一个的文件句柄

除了 DATA 之外(它总是每个包一个),如果下面的文件句柄没有用其他包名字修饰的话,那就
总是假设在 main 里:

_(下划线)
...(略)

**每个包一个的特殊函数

下面的子过程名字对 Perl 有特殊含义。它们总会因为某些事件而隐含地调用,这些事件可以是
访问一个捆绑的变量或者试图调用一个未定义的函数等等。我们不会在本章描述它们,因为它们在
本书的其它部分已经多次提到了。

未定义函数调用拦截器(参阅第十章,包)

AUTOLOAD

垂死的对象的终结(参阅第十二章,对象):

DESTROY

例外对象(参阅下一章的 die):

PROPAGATE

自动初始化和自动清理函数(参阅第十八章,编译):

BEGIN,CHECK,INIT,END

方法(参阅第十四章):

BINMODE,CLEAR,
...(略)

**按照字母顺序排列的特殊变量

我们根据长变量名的字母顺序排列了这些变量。如你不知道这些变量的长名字,你可以在前一节里
找到它们。(没有字母名字的变量在前面排列。)

所以这里我们就不用再次重复了,每个变量的描述以下面的注解中的一个或多个开头:

注解 | 含义


XXX | 废弃了,不要在任何新程序里再用
NOT | 并不正式存在(只用于内部)
ALL | 真正的全局量,由所有包共享
PKG | 包全局变量;每个包都有自己的一套
FHA | 文件句柄属性;每个 I/O 对象一个
DYN | 自动处于动态范围内(隐含 ALL)
LEX | 编译时的词法范围
RO | 只读,如果你修改它会抛出一个例外

如果列出了多于一个变量名或者符号,那么缺省时只有短名字可以使用。使用 English 模块可以
让当前包里可以用长的同义词,但只有当前包可以用,即使该变量标记着 [ALL] 也如此。

形如 method HANDLE EXPR 这样的记录显示了那些每个文件句柄变量一个的面向对象的接口,
这些变量是 FileHandle? 和各种 IO:: 模块提供的。(如果你愿意,你还可以使用
HANDLE->method(EXPR) 表示法。)这些变量让你在检查或者改变该变量之前可以避免调用
select 来改变缺省输出句柄。每个这样的句柄都返回 FileHandle? 属性的旧数值;如果提供了
EXPR,那么就会设置一个新值。如果没有提供 EXPR,大多数这些方法对当前变量不做任何事情
——除 autoflush 外,它会假设一个参数 1,以示区别。

_(下划线)
[ALL] 这是一个特殊的文件句柄,用于缓存上一次成功的 stat,lstat,或者文件测试
操作符(比如 -w $file 或 -d $file)的信息。

$digits
[DYN, RO] 编号变量 $1,$2,等等(数字可以大到你想要的任何数目)(注:尽管许多
正则表达式引擎只能支持最多九个后引用,Perl 可没有这样的限制,所以如果你用到
$768,Perl 也不会在意,只不过是如果你在正则表达式里用了这么多圆括弧的话,
你的代码的维护人可能会介意。),它们包含在当前活跃动态范围里上一次模式匹配中
对应的圆括弧集的匹配文本。(记忆方法:象 \digits。)

$[ [XXX,LEX] 数组中的第一个元素的索引和子字串中第一个字符。缺省是 0,不过我们通常
设置为 1,这样 Perl 在处理脚标和计算 index 和 substr 函数时的行为就更象 awk
(或者 FORTRAN)。因为后来我们发现这么干很危险,所以现在给 $[ 赋值被当作是词法
范围里编译器的指示器,并且不能影响任何其他文件的行为。(记忆方法:[ 开始一个
下标。)

$# [XXX,ALL] 不要用这个变量了,用 printf 代替。$# 包含打印出去的数字的输出格式,
它是我们想模拟 awk 的 OFMT 变量的有因无果的一个东西。(记忆方法:# 是数字符号,
不过如果你很聪明,那么就忘掉它好了,这样你就不会因把你的程序搞得乱七八糟而苦恼。

$* [XXX,ALL] 哇,三个废弃了的变量在一行里!这个东西可以(但是不应该)设置为真,
好让 Perl 对每个没有明确 /s 的模式匹配都假设一个 /m。(记忆方法:* 匹配多个
东西。)

$a [PKG] 这个变量被 sort 函数用于保存需要比较的每一对数值的第一个($b 是每一对的
第二个)。$a 所在的包就是 sort 操作符编译进去的那个包,这个包不一定和它的比较
函数编译进去的那个包一样。这个变量在 osrt 比较块里会被隐含的局部化。因为它是
一个全局量,所以它不会让 use strict 发出警告。因为它是实际数组数值的一个别名,
所以你可能会认为你可以改变它,但是你不能,参阅 sort 函数。

$ACCUMULATOR
$^A
[ALL] write 累积器写 format 行的当前值。一个格式包含把它们的结果放到 $^A 中去
的 formline 命令。在调用完它的格式之后,write 把 $^A 的内容打印出来然后清空
它。所以你从来看不到 $^A 的内容,除非你自己调用 formline 并且查看它。参阅
formline 函数。

$ARG
$_ [ALL] 缺省的输入和模式搜索空间。下面各对是相等的:

while(<>) {...} # 只是在没有修饰的 while 测试中相等
while (defined($_ = <>)) { ... }

...(略)

下面是一些在你没有声明需要操作的东西的时候,Perl 会假设是 $_ 的地方:

* print 和 unlink 这样的列表函数,以及象 ord,pos,和 int 这样的单目函数,
还有所有文件测试(除了 -t 以外,它的缺省是 STDIN)。所有缺省是 $_ 的函数也在
第二十九章,函数,里做了标记。

* 模式匹配操作符 m// 和 s//,以及没有使用 =~ 操作符时的转换操作符 y/// 和
tr///。

* 在 foreach 循环里,如果没有提供其他变量,那么遍历变量缺省也是 $_(甚至在用
for 或者用做一个语句修饰词的时候也是它)。

* 在 grep 和 map 函数里的隐含的遍历变量。(在那里没有办法用其他变量干这件事。)

* 如果一个 ,readline,或者 glob 操作符的结果本身作为 while 测试的唯一
标准的时候,缺省的放输入记录的地方也是 $_。这个赋值不是在 while 测试外部
发生的,如果在 while 表达式里还有任何其他的元素,也不是在 while 测试外面赋值。

(记忆方法:下划线(underline)是某种操作下(underlying)的操作数。
译注:英文 underlying 的意思是“当前...的”,和英文的下划线"underline"同音。)

@ARG
@_ [ALL] 在一个子过程里,这个变量保存传递给子过程的参数列表。参阅第六章,子过程。
在标量环境里的分割可以把这个数组分割开,但是这个用法已经废弃了。

ARGV
[ALL] 特殊的文件句柄,它遍历在 @ARGV 里的所有命令行文件名。通常写成尖角操作符
里的空文件句柄:<>。

$ARGV
[ALL] 当使用 <> 或者 readline 操作符从 ARGV 句柄里读取数据的时候,包含当前
文件名。

@ARGV
[ALL] 这个数组包含传递给脚本的命令行参数。请注意 $#ARGV 通常是参数的数目减一,
因此 $ARGV[0] 是第一个参数,而不是命令名;用 scalar @ARGV 获取程序参数的数目。
从 $0 中获得文件名。

ARGVOUT
[ALL] 当你在 -i 开关或者 $^I 变量下处理 ARGV 句柄时使用这个特殊的文件句柄。
参阅第十九章,命令行接口。

$b [PKG] 这个变量和 $a 一起用于在 sort 里做比较。参阅 $a 和 sort 函数获取细节。

$BASETIME
$^T
[ALL] 该脚本开始运行的时间,是自纪元以来的秒数(对于 Unix 系统而言是 1970 年
开始)。-M,-A 和 -C 文件测试返回的数值是与这个时间的相对值。

$CHILD_ERROR
$? [ALL] 上一次管道关闭,反勾号(``)命令或者 wait,waitpid,或者 system 函数
返回的状态。请注意它不仅仅是简单的退出代码,而是由下层的 wait(2) 或者
waitpid(2) 系统调用返回的完整的 16 位状态。因此,子过程的退出值在高位,也就是
$? >> 8;在低位,$? & 127 告诉你该进程是因为哪个信号(如果有)退出的,而
$? & 128 汇报该进程的死亡是否产生一个内核的倾倒。(记忆方法:类似 sh 和其
变体的 $? 。)

在 END 块里,$? 包含将要赋值给 exit 的数值。你可以在 END 里修改 $? 的值来改变
脚本的退出状态。

在 VMS 里,这个用法使用 use vmsish 'status' 令 $? 反映真正的 VMS 的退出状态,
而不是缺省的 POSIX 状态的仿真。

$COMPILING
$^C
[ALL] 与 -c 开关相关联的内部标记的当前数值,主要是和 -MO 和 perlcc(1) 工具
一起使用,好让代码在为代码生成编译的时候修改自身的行为。比如,你可能想在编译
时就 AUTOLOAD,而不是使用普通的延迟装载,这样代码就可以马上生成。参阅第十八章。

DATA
[PKG] 这个特殊的文件句柄指向当前文件中任何跟在 END 或者 DATA 记号后面
的东西。__END__ 记号总是打开 main::DATA 文件句柄,因此它是在主程序中使用。
DATA 记号在任何当前起作用的包中打开 DATA 句柄,因此不同的模块可以有自己的
DATA 文件句柄,因为(可以假定)它们有不同的包名字。

$DEBUGGING
$^D
[ALL] 内部调试标志的当前值,是从命令行上的 -D 开关设置的;参阅第十九章获取
它的位数值。(记忆方法:-D 开关的数值。)

$EFFECTIVE_GROUP_ID
$EGID
$) [ALL] 该进程有效的 GID(组 ID)。如果你用的机器同时支持多个组的成员关系,那么 $)
给出了你所处的一个用空格分隔的组的列表。第一个数字是 getegid(2) 的返回,而随后
的是 getgroups(2) 的返回,其中之一可能与第一个数字相同。

类似地,给 $) 的赋值也必须是一个空格分隔的数字列表。第一个数字用于设置有效的
GID,其他的传递给 setgroups(2) 系统调用。要获得给 setgroups 一个空列表的
效果,你只需要重复新的有效 GID;比如,强制一个有效 GID 为 5 和一个空的有效
setgroups 列表,说:

$) = "5 5";

(记忆方法:圆括弧是用于给东西分组的。如果你运行在 setgid 下,有效的 GID 是你
正(right:英文中与“右”同形)处在的组)注意:$,$(,和 $) 只能在那些
支持对应的系统 set-id 过程的机器上使用。$( 和 $) 只能在那些支持 setregid(2)
的机器上对换使用。

$EFFECTIVE_USER_ID
$EUID
$> [ALL] 这个进程的有效的 UID,和 geteuid(2) 系统调用返回的一样。例子:

$< = $>; # 把真实 uid 设置为有效 uid
($) = ($>,$<); # 交换真实和有效 uid

(记忆方法:如果你在 setid 下运行,它是你前往的 UID。)注意:$< 和 $> 只能在那些
支持 setreuid(2) 的机器上交换使用。而且有时候甚至那些支持的机器也不能交换。

%ENV
[ALL] 包含你的当前环境变量的散列。在 %ENV 里设置一个数值同时改变了你的进程和
在这个赋值之后派生的子进程的环境。(在任何类似 Unix 的系统里,它都不能改变
父进程的环境。)

$ENV{PATH} = "/bin:/usr/bin";
$ENV{PAGER} = "less";
$ENV{LESS} = "MQeicsnf"; # 我们最喜欢的给 less(1) 的开关
system "man perl"; # 选择新的设置

要从你的环境中删除内容,请记住在散列数值上使用 delete 函数而不是 undef 。

请注意作为 crontab(5) 记录运行的进程继承了一个非常贫瘠的环境变量集。(如果你的
程序在命令行上运行得很好但在 cron 下运行的很糟,那么原因可能就是这个。)还要
注意,如果你在作为一个 setuid 脚本运行,你还应该设置 $ENV{PATH},$ENV{SHELL},
$ENV{BASH_ENV},和 $ENV{IFS}。参阅第二十三章,安全。

$EVAL_ERROR
$@ [ALL] 上一次 eval 操作抛出的当前例外或者 Perl 语法错误信息。(记忆方法:语法
错误“at”(在)哪里?(译注:@ 是“at”的意思。))和 $! ($OS_ERROR)不同,
它是在失败的时候设置的,但是成功的时候并不清除,而如果上一次 eval 有编译错误
或者运行时例外的时候,$@ 是保证要设置的(为一个真值),并且如果没有这些问题
发生,也是保证被清除的(成一个假值)。这个变量里不会收集警告信息。不过,你可以
通过设置一个路径处理警告,方法是按照我们本节 稍后描述的方法设置
$SIG{__WARN__}。

请注意 $@ 的数值可能是一个例外对象而不是一个字串。如果是这样,而且该例外对象
有为其对象类定义的字串化重载的话,你可能仍然可以把它当作字串对待。如果你通过
说:

die if $@;

传播一个例外,那么一个例外对象就会调用 $@->PROPAGATE 以查找要做的动作。(一个
字串例外只是向该字串增加一个“propagated at”行。)

$EXCEPTIONS_BEING_CAUGHT
$^S
[ALL] 这个变量反映解释器的当前状态,如果是在一个 eval 里面,则返回真,否则返回
假。如果当前的编译单元尚未完成,那么它就是未定义,这种情况可能是在
$SIG{__DIE__} 和 $SIG{__WARN__} 文件句柄里的情况。(记忆方法:eval 的状态。)

$EXECUTABLE_NAME
$^X
[ALL] perl 二进制文件本身执行的名字,来自 C 的 argv[0]。

@EXPORT
[PKG] Exporter 模块的 import 方法会查看这个数组变量,寻找当这个模块被 use 的
时候,或者使用了 :DEFAULT 输入标记的时候,缺省时需要输出的其他包变量和子过程。
它无法免除 use strict 的检查,所以,如果你打开了 use strict 用法,那么你必须
用 our 声明它或者使用带包名字的全称。不过,那些以字串“EXPORT”开头的所有变量
如果只使用一次的话,都免于警告的检查。参阅第十一章,模块。

@EXPORT_OK
[PKG] Export 模块的 import 方法会查看这个变量以判断一个请求的输入是否合法。
它不能免于 use strict 的检查。参阅第十一章。

%EXPORT_TAS
[PKG] 当用户请求一个前导冒号的输入符号的时候,比如 use POSIX ":sys_wait_h",
Exporter 的 import 方法会检查这个散列变量。这时候键字是这个冒号标签,但是没有
前面的冒号。当请求这个冒号标签的时候,其值应该是一个包含将要输入的符号的数组
引用,所有这些变量也必须出现在 @EXPORT 或者 @EXPORT_OK 里。它不能免于
use strict 的检查。参阅第十一章。

$EXTENDED_OS_ERROR
$^E
[ALL] 与当前操作系统相关的错误信息。在 Unix 里,$^E 等效于 $!($OS_ERROR),
但它在 OS/2,VMS,和 Microsfot 系统,以及 MacPerl? 里是不一样的。参考你的
Perl 版本获取详细描述。在 $! 里提到的注意事项通常也适用于 $^E。(记忆方法:
额外的错误解释。)

@F [PKG] 如果给出了 -a 命令行开关,它就是存放分裂后的输入行数据域的数组。如果没有
使用 -a 选项,这个数组就没有特殊含义。(这个数组实际上只是 @main::F,并且马上
就会在所有其他包中消失。)

%FIELDS
[NOT,PKG] 这个散列是被 use fields 用法在内部使用的,用于判断目标散列的当前
合法的字段。参阅第十二章里的, use fields,use base,和“用 use fields
定义的域”。

format_formfeed HANDLE EXPR
$FORMAT_FORMFEED
$^L
[ALL] 在 write 函数写一个表格的头部之前它隐含输出的用于换页的东西。缺省是
“\f”。

format_lines_left HANDLE EXPR
$FORMAT_LINES_LEFT
$- [FHA] 当前选定的输出句柄在页面上留下的行数,与 format 声明和 write 函数一起
使用。(记忆方法:lines_on_page - lines_printed。)

format_lines_per_page HANDLE EXPR
$FORMAT_LINES_PER_PAGE
$= [FHA] 当前选定的输出句柄的当前页长(可打印行数),和 format 和 write 一起
使用。缺省是 60。(记忆方法:= 是水平行数。)

format_line_break_characters HANDLE EXPR
$FORMAT_LINE_BREAK_CHARACTERS
$: [ALL] 在一个格式里,如果一个字串需要断开以保持连续域(以 ^ 开头),这时候用的
断开字符集。缺省是“ \n-”,用来在空白或者连字符上断开。(记忆方法:冒号在诗歌
里是一个技术词汇,表示一行的一部分。现在你只需要记住这个方法就可以了...)

format_name HANDLE EXPR
$FORMAT_NAME
$~ [FHA] 当前选定的输出句柄的当前报表格式的名字。缺省是该文件句柄的名字(记忆方法:
在 $^ 后面拐个弯。)

format_page_number HANDLE EXPR
$FORMAT_PAGE_NUMBER
$% [FHA] 当前选定的输出句柄的饿当前页码,与 format 和 write 一起使用。(记忆
方法:% 是 troff(1) 里的页码寄存器。什么!你不知道 troff 是什么?)

format_top_name HANDLE EXPR
$FORMAT_TOP_NAME
$^ [FHA] 当前选定输出句柄的页顶格式的名字。缺省是后缀 _TOP 的文件句柄的名字。
(记忆方法:指向页面顶部。)

$^H
[NOT,LEX] 这个变量为 Perl 分析器保存词法范围里的状态位(也被叫做“暗示”)。
这个变量是严格地只在内部使用的。它的可用性,行为,和内容都是可能在不加任何通知
的情况下修改的。如果你动了他,那么你就会患上科学家未知的某种可怕的热带疾病而
完蛋。(记忆方法:我们 不想给你提示。)

%^H
[NOT,LEX] %^H 散列提供和 $^H 一样的词法范围的语意,这样它就可以用于实现词法
范围的程序。请阅读在 $^H 里列出的可怕的警告,并且我们还要加上一条,就是这个
变量仍然是实验性的。

%INC
[ALL] 这个散列包含每个 Perl 文件通过 do FILE,require,或 use 装载的文件名。
键字是你声明的文件名,而数值是实际找到该文件的位置。require 操作符使用这个数组
判断某个文件是否已经被 装载了。比如:

%perl -MLWP::Simple -le 'print $INC{"LWP/Simple.pm"}'
/opt/perl/5.6.0/lib/site_perl/LWP/Simple.pm

@INC
[ALL] 这个数组包含一个目录的列表,Perl 模块可能通过 do FILE,require,或 use
寻找这些目录。它初始的时候包含任何 -I 命令行开关和在 PERL5LIB 环境变量里的
目录,后面跟着缺省的 Perl 库,比如:

...(略)

最后跟着“.”,代表单前目录。如果你需要从你的程序里面修改这个列表,试着使用
use lib 用法,它不仅在编译时修改该变量,而且还追加任何相关的体系相关的目录
(比如那些包含 XS 模块使用的共享库的目录):

use lib "/mypath/libdir/";
use SomeMod?;

$INPLACE_EDIT
$^I
[ALL] 现场编辑扩展的当前值。使用 undef 关闭现场编辑。你可以在你的程序内部使用
这个变量以获取和 -i 开关提供的相同的行为。比如,要实现和下面命令相同的功能:

%perl -i.orig -pe 's/foo/bar/g' *.c

你可以在你的程序里使用等效的代码:

local $^ = '.orig';
local @ARGV = glob("*.c");
while(<>) {
s/foo/bar/g;
print;
}

(记忆方法:-i 开关的值。)

$INPUT_LINE_NUMBER
$NR
$. [ALL] 你最后读取(或者在其上调用了 seek 或 tell )的文件句柄的当前记录数目
(通常是行数)。该值可能与文件中实际的物理行数不同——取决于实际有效的“行”的
概念是什么——参阅 $/ ($INPUT_RECORE_SEPARATIO)获取如何影响该行为的方法。
在文件句柄上的明确的关闭动作将重置这个行数。因为 <> 从来不会做明确关闭动作,
所以行数在 ARGV 文件间递增(但是请参阅 eof 里的例子)。局部化 $. 同时也局部化
了 Perl 的“最后阅读的文件句柄”的概念。(记忆方法:许多程序使用“.”表示当前
行数。)

$INPUT_RECORD_SEPARATOR
$RS
$/ [ALL] 输入记录分隔符,缺省是换行符,readline 函数, 操作符,和 chomp 函数
会使用它。它的作用类似 awk 的 RS 变量,并且如果你把它设置为空字串,它就把一个
或者多个空白行当作一个记录终止符。(不过空白行必须没有任何隐藏的空格或水平
制表符。)你可以把它设置为一个多字符字串以匹配一个多字符终止符,但是你不能为
一个模式设置它—— awk 怎么着也会在某些事情上有些优点。

请注意,如果一个文件包含连续的空白行,那么把 $/ 设置为“\n\n”的含义和把它设置
为“”略有区别。把它设置为“”将把两个或者更多的连续空白行当作一个空白行。而
设置为“\n\n”意味着 Perl 将盲目地把第三个换行当作下一段的内容。

完全取消 $/ 的定义将令下一行的输入操作把剩余的文件内容当作一个标量数值一次吃进:

undef $/; # 打开全文件模式
$_ = ; # 现在整个文件在此
s/\n[ \t]+/ /g; # 删除缩进的行

如果你在 $/ 是未定义的时候使用 while(<>) 构造来访问 ARGV 句柄,那么每次读取都
会读取下一个文件的内容:

undef $/;
while(<>) { # $_ 里有下一个文件的所有内容
...
}

尽管我们在上面使用了 undef,但是更安全的做法是用 local 解除一个 $/ 的定义:

{
local $/;
$_ = ;
}

如果把 $/ 设置为一个引用,该引用指向一个整数,或者一个保存着整数数值的标量,
或者一个可以转换成一个整数的标量,那么都会令 readline 和 操作符读取固定
长度的记录(其最大记录长度是引用的整数数值),而不是读取由特定字串终止的变长
记录。所以:

$/ = \32768; # 或者 \"32768" 或者 \$scalar_var_containing_32768
opoen(FILE, $myfile);
$record = ;

将从 FILE 句柄里读进不超过 32,768 字节的一条记录。如果你不是从一个面向记录的
文件里读取(或者你的操作系统里没有面向记录的文件),那么你就很有可能每次读取
动作都获取一整段数据。如果一条记录比你设置的记录尺寸还要大,那么你就会分段地
获得该记录。只有那些标准的 I/O 支持 read(3) 函数的系统上,记录模式才能和行
模式混合良好;VMS 就是一个显著的例外。

当 $/ 设置成打开记录模式——或者它被解除定义的时候,调用 chomp 没有任何作用。
又见第十九章里的命令行开关 -0(数字零)和 -l(字母 L 的小写)。(记忆方法:
当你引用诗歌的时候,/ 用于分隔行。)

@ISA
[PKG] 如果在当前包中不能找到一个方法调用的时候,这个数组包含需要查找的其他包的
名字。也就是说,它包含该包的基础类。use base 用法隐含地这些这个变量。它不能
免除 use strict 的检查。参阅第十二章。

@LAST_MATCH_END
@+ 这个数组保存在当前活跃的动态范围里,与上一次的成功子匹配的结尾之间的偏移量。
$+[0] 是与整个匹配结尾之间的偏移量。这个值与你对正在匹配的变量调用 pod 函数
返回的数值是一样的。(在我们说“与结尾之间的偏移量”的时候,我们实际的意思是与
跟在刚匹配完的东西后面第一个字符之间的偏移,这样我们就可以从开头偏移中减去结尾
偏移,并得到长度。)这个数组的第 n 个元素保存第 n 个子匹配的偏移量,所以 $+[1]
就是 $1 结束的偏移量,$+[2] 就是 $2 结束的偏移量,等等。你可以使用 $#+ 判断上
一次成功的匹配里有多少个子组。参阅 @-(@LAST_MATCH_START)。

在对某变量 $var 的一次成功的匹配之后:

* $` 与 substr($var, 0, $-[0]) 相同
* $& 与 substr($var, $-[0], $+[0] - $-[0]) 相同
* $' 与 substr($var, $+[0] ) 相同
* $1 与 substr($var, $-[1], $+[1] - $-[1]) 相同
* $2 与 substr($var, $-[2], $+[2] - $-[2]) 相同
* $3 与 substr($var, $-[3], $+[3] - $-[3]) 相同,以此类推。

@LAST_MATCH_START
@- [DYN,RO] 这个数组保存在当前活跃的动态范围里,与上一次的成功子匹配的开头之间的
偏移量。$-[0] 是与整个匹配开头之间的偏移量。这个数组的第 n 个元素保存第 n 个
子匹配的偏移量,所以 $-[1] 就是 $1 开头的偏移量,$-[2] 就是 $2 开头的偏移量,
等等。你可以使用 $#- 判断上一次成功的匹配里有多少个子组。参阅
@+(@LAST_MATCH_END)。

$LAST_PAREN_MATCH
$+ [DYN,RO] 这个变量返回在当前活跃动态范围里,上一次成功模式的最后一个圆括弧
子匹配。如果你不知道(或者不关心)一套候选模式中的哪个匹配上了,那么它就很有用。
(记忆方法:要积极(译注:positive,英文“+”号的单词)并且向前看。)例子:

$rev = $+ if /Version: (.*)|Revision: (.*)/;

$LAST_REGEXP_CODE_RESULT
$^R
[DYN] 这个变量包含在一个有 (?{ CODE }) 构造的成功匹配的模式里面,最后一段
代码的执行结果。$^R 给予你一个执行代码并且把执行结果记住为稍后的模式使用的
方法,或者甚至是模式之后使用。

当 Perl 的正则表达式引擎在模式中移动的时候,它可能多次碰到 (?{CODE}) 表达式。
在引擎的处理过程中,它记住每个 $^R 的数值,因此,如果它在后面必须回朔一个
表达式,它就可以恢复前面一个 $^R 的数值。换句话说,$^R 在模式里有一个动态
范围,很象 $1 及其同党。

因此 $^R 并不只是在一个模式里执行的最后一段代码的结果。它是导致成功匹配的最后
一段代码的结果。一个必然的推论就是如果该匹配没有成功,那么 $^R 就会恢复成在
模式匹配发生之前它的数值。

如果 (?{ CODE }) 模式直接作为一个 (?(COND) IFTRUE|IFFALSE) 的条件作用,那么
不会设置 $^R。

$LIST_SEPARATOR
$" [ALL] 如果一个数组或者数组片段被代换到一个双引号字串里(或者类似的东西),这个
变量就是在独立的元素之间要放的字串。缺省是一个空格。(记忆方法:显然,我们希望
是这样。)

$^M
[ALL] 缺省时,用光内存是不可捕获的。不过,如果你的 perl 编译成利用 $^M 的
优点,那么你可以把它用做一个应急存储器池。如果你的 Perl 是带着
-DPERL_EMERGENCY_SBRK 并且使用 Perl 的 malloc,那么:

$^M = 'a' x (1<<16);

将分配一个 64K 的缓冲区用于紧急状态。参阅 Perl 源程序目录里的 INSTALL 文件
获取如何打开这个选项的信息。

为了让你小心地使用这个高级特性,我们给你设置了一些障碍:这个变量没有
use English 长名字(并且我们也不会告诉你怎么记忆。)

$MATCH
$& [DYN,RO] 在当前活跃的动态范围里,这个变量里是上一次成功的模式匹配匹配的字串。
(记忆方法:就象在一些编辑器里的 & 一样。)

$OLD_PERL_VERSION
$] [ALL] 返回版本号+补丁级别/1000。你可以用它在脚本的开始处判断执行该脚本的
Perl 解释器的版本是否落在正确的范围里。(记忆方法:这个版本的 Perl 在右方括弧
里吗?)例子:

warn "no checksumming!\n" if $] < 3.019;
die "Must have prototyping available\n" if $] < 5.003;

又见 use VERSION 和 require VERSION 的文档,寻找一种当 Perl 解释器版本太老的
时候的便利的失效方法。参阅 $^V 获取更灵活的 Perl 版本的 UTF-8 的表现形式。

$OSNAME
$^O
[ALL] 这个变量包含当前 perl 二进制文件为之编译的平台的名字(通常是操作系统名字
)。它是从 Config 模块中抽取同样信息的低成本替代品。

$OS_ERROR
$ERRNO
$! [ALL] 如果在一个数字环境中使用,产生上一次系统调用错误的当前值,适用所有常见
注意事项。(这就意味着除非你拿到的某个返回值就表明是一次系统错误,否则你不能
倚赖 $! 的值做任何事情。)如果你在一个字串环境里使用它,$! 就生成对应的系统
错误字串。比如,如果你希望 $! 返回某特定错误的字串,或者你想为 die 设置退出
值,那么你可以给 $! 赋予一个错误数字。又见第三十二章的 Errno 模块。(记忆方法:
刚才错误是什么?)

%OS_ERROR
%ERRNO
%! [ALL] 这个散列只有在你装载了第三十二章里描述的 Errno 模块之后才定义。一旦你
做了装载工作,那么你就可以给 %! 一个特定的错误字串做脚标,并且只有它是当前
错误的时候,其值才为真。比如,只有 C 的 errno 变量当前设置为 C #define 值,
ENOENT 的时候,$!{ENOENT} 才为真。这样就可以很方便地访问与供应商相关的符号。

autoflush HANDLE EXPR
$OUTPUT_AUTOFLUSH
$AUTOFLUSH
$| [FHA] 如果设置为真,则强制当前选定的输出句柄在每次 print,printf,和 write
之后都进行缓冲区冲刷。(我们把这个动作称做命令缓冲。与流行的看法相反,设置这个
变量并不关闭缓冲。)缺省是假,在许多系统上这就意味着如果输出是到终端的,那么
STDOUT 就是行缓冲,否则就是块缓冲,甚至在管道和套接字上也是如此。如果你在向
一个管道输出的时候,(比如你通过 rsh(1) 运行一个 Perl 脚本并且想在脚本运行的
时候就可以看到其输出。)那么设置这个变量就非常有用。当你设置这个变量为真的
时候,如果你的当前选定文件句柄的输出缓冲区里有挂起的为冲刷的数据,那么该缓冲区
就会被立即冲刷,这是赋值动作的副作用。参阅单参数形式的 select ,获取一个控制
STDOUT 以外的文件句柄的缓冲的例子。(记忆方法:当你想让你的管道不停泵取数据的
时候。)

这个变量对输入缓冲没有任何影响;为了影响输入缓冲,参阅第二十九章的 getc 或者在
第三十二章 POSIX 模块里的例子。

$OUTPUT_FIELD_SEPARATOR
$OFS
$, [ALL] 用于 print 的输出字段分隔符(实际上是结束符)。通常,print 只是简单地
打印出你声明的列表元素,在它们中间不加任何东西。按照设置 awk 的 OFS 变量的
方法设置这个变量,声明你想在字段之间打印什么东西。(记忆方法:当你的 print
语句里有一个“,”的时候打印的东西。)

$OUTPUT_RECORD_SEPARATOR
$ORS
$\ [ALL] 用于 print 的输出记录分隔符(实际上是结束符)。通常,print 只是简单地
打印出你声明的逗号分隔的字段,并不假设任何结尾的新行或者记录分隔符。按照设置
awk 的 ORS 变量的方法设置这个变量,声明在 print 结束的时候打印什么东西。
(记忆方法:你设置 $\ 代替在 print 结尾追加 “\n”。同样,它也很象 /,但它是
你从 Perl 里“拿回来”的东西。)又见第十九章里的 -l(是“line”的意思)命令行
开关。

%OVERLOAD
[NOT,PKG] 这个散列的记录是 use overload 用法在内部设置的,用于为当前包的类
对象实现操作符重载。参阅第十三章,重载。

$PERLDB
$^P
[NOT,ALL] 打开 Perl 调试器的内部变量(perl -d)。

$PERL_VERSION
$^V
[ALL] Perl 解释器的修订版,版本,和子版本,是用二进制的“版本字串”表示的。
V-字串通常没有数字值,但这个变量有双值,有一个数字值等于老的 $] 变量;也就
是说,一个浮点数,数值是 修订版 + 版本/1000 + 子版本/1,000,000。其字串值是从
UTF-8 字符来的:chr($revision) . chr($version) . chr($subversion)。这就
意味着 $^V 是不可打印的。要打印它,你必须说:

printf "%vd", $^V;

从正面来说,它还意味着你可以使用普通的字串比较来判断执行你的脚本的 Perl 解释器
是否在正确的版本范围里。(这个功能适用于任何代表 v-字串的版本数字,而不仅仅是
Perl 的。)例子:

warn "No 'our' declarations!\n" if $^V lt v5.6;

参阅 use VERSION 和 require VERSION 的文档,寻找一种当运行的 Perl 解释器比你
希望的版本老的时候失效的一种便利方法。又见 $],看看 Perl 版本的最初的表现形式。

$POSTMATCH
$' [DYN,RO] 这个变量里保存在当前活跃的动态范围里,上一次成功匹配里跟在匹配字串
后面的字串。(记忆方法:' 常跟在一个引起的字串后面。)例子:

$_ = 'abcdefghi';
/def/;
print "$`:$&:$'"; # 打印 abc:def:ghi

因为在动态范围里,Perl 不知道哪个模式需要将它们的结果保存到这里变量里,所以在
程序里的任何位置提及 $` 或 $' 都将导致在程序里的所有模式匹配的性能损失。对于
小程序而言,这些算不上 什么,但是如果你是在写可以复用的模块代码,那么你可能就
应该避免使用这一对儿。上面的例子可以用下面的代码代替,但是不会遭受全局的性能
损失:

$_ = 'abcdefghi';
/(.*?)(def)(.*)/s; # /s 以防 $1 包含换行符
print "$1:$2:$3\n"; # 打印 abc:def:ghi

$PREMATCH
$` [DYN,RO] 这个变量里保存在当前活跃的动态范围里,上一次成功匹配里在匹配字串前面
的字串。(记忆方法:` 通常放在一个引起字串的前面。)参阅前面的 $' 里性能损失的
描述。

$PROCES_ID
$PID
$$ [ALL] 运行这个脚本的 Perl 的进程号(PID)。在 fork 的时候,这个变量会自动
更新。实际上,你甚至可以自己设置 $$;不过,这么干不会改变你的 PID。要改变 PID
将是一个漂亮的窍门。(记忆方法:和各种 shell 里一样。)

你需要注意的是不要在任何可能错误地解释成一个析引用的地方使用 $$:$$alphanum。
在这个情况下,要写${$}alphanum 以便与 ${$alphanum} 相区别。

$PROGRAM_NAME
$0 [ALL] 包含存放正被执行的 Perl 脚本的文件的文件名。给 $0 赋值是一个神奇的操作:
它试图修改通常 ps(1) 程序报告的参数区域。这种赋值作为一种标识当前程序状态的
方法可能要比隐藏你运行的程序更有用些。不过这个赋值不能在所有系统上运行。(记忆
方法:和 sh,ksh,bash,等等里一样。)

$REAL_GROUP_ID
$GID
$( [ALL] 这个进程的真实组 ID(GID)。如果你运行的平台支持同时在多个组里的成员
关系,$( 给出一个相互分隔的,你所处的组列表。第一个数字是 getgid(2) 返回的
数值,随后的就是 getgroups(2) 返回的,其中之一可能和第一个数字相同。

不过,给 $( 赋值的时候,这个值必须是用于设置真实 GID 的单个数字。所以 $( 给出
的数值不能在没有强制成数字(比如加个零)之前给回 $(,这是因为你只能有一个真实
组。参阅 $) ($EFFECTIVE_GROUP_ID)替换品,它总是允许你设置多个有效的组。

(记忆方法:圆括弧是用于分组的。如果你运行在 setgid 下,真实 GID 是你离开的组
(译注:英文“left”有“离开”之意,同时又是“左边”的同型词。))

$REAL_USER_ID
$UID
$< [ALL] 这个进程的真实用户 ID(UID),和 getuid(2) 系统调用返回的一样。你是否
能修改这个数值以及你怎样修改这个数值随着你的系统实现的变化而变化——参阅 $>(
$EFFECTIVE_USER_ID)里的例子。(记忆方法:如果你运行在 setuid 下,这是你来自
的地方。)

%SIG
[ALL] 这个散列用于给各种信号设置信号句柄。(参阅第十六章,进程间通讯,里的
“信号”一节)比如:

sub handler {
my $sig = shift; # 第一个参数是信号名字
syswrite STDERR, "Caught a SIG$sig--shutting down\n";
# 避免在异步句柄里的标准 I/O 以避免内核倾倒。
# (甚至字串连接都是危险的。)
close LOG; # 这里调用标准 I/O,所以可能内核倾倒!
exit 1; # 不过既然我们正在退出,所以也没什么损失了。
}

$SIG{INF} = \&handler;
$SIG{QUIT} = \&handler;
...
$SIG{INT} = 'DEFAULT'; # 恢复缺省动作
$SIG{QUIT} = 'IGNORE'; # 忽略 SIGQUIT

%SIG 散列包含与那些还没有设置句柄的信号的未定义的数值。一个句柄可以作为一个
子过程引用或者一个字串声明。如果一个字串的值不是两个特殊动作“DEFAULT”或
“IGNORE”之一的时候,它就是一个函数的名字,如果这个名字不是带包名的全称,那么
就会解释为在 main 包里。下面是其他一些例子:

$SIG{PIPE} = "Plumber"; # 正确,假设为 main::Plumbr
$SIG{PIPE} = \&Plumber; # 很好,使用来自当前包的 Plumber

还可以用 %SIG 散列设置一些内部挂钩。如果要打印一条警告信息的话,那么就会调用
$SIG{__WARN__} 标识的过程。这条警告信息被当作第一个参数传递。一个 WARN
挂钩的存在导致给 STDERR 的通常的打印动作被消除。你可以用他把警告保存在一个
变量里,或者把警告转化成一个致命错误,象这样:

local $SIG{__WARN__} = sub { die $_[0] };
eval $proggie;

这样做类似于说:

uas warnings qw/FATAL all/;
eval $proggie;

只不过前一个有动态范围,而第二个有词法范围。

$SIG{__DIE__} 标识的过程提供了一个用魔术般的一吻把青蛙例外转变成王子例外的
方法,不过,经常不能运行。

它的最好的用途就是在一个准备死在一个未捕获的例外的的程序上,在它临终的时候做
一些临终处理。用这个方法也救不了你,但是你可以最后再喊一句口号。

例外信息被当作第一个参数传递进来。当一个 DIE 挂钩过程返回的时候,例外处理
会象没有挂钩一样继续处理,除非挂钩过程本身通过一个 goto,一个循环退出或者一个
die 退出。在调用的过程中 DIE 句柄被明确地关闭,所以然后你自己就可以从一个
DIE 句柄里调用真正的 die。(如果它没有关闭,那么句柄会永远递归地调用
自己。)$SIG{__WARN__} 句柄的运转状况类似。

只有主程序可以设置 $SIG{__DIE__},模块不能。这是因为在目前,甚至那些被捕捉的
例外也仍然触发一个 $SIG{__DIE__} 句柄。我们强烈反对设置这个句柄,因为这样做
可能破坏那些无辜的模块:这些模块正在等待它们预期的例外的时候,那些例外却被莫名
其妙地被修改了。你应该只是把这个特性当作最后的手段,而且如果你必须这么做,应该
总在前面放一个 local 以限制危险的时期。

不要试图在这个特性上制作例外处理机制。你应该用 eval {} 捕获那些例外。

STDERR
[ALL] 用于在任何包里做标准错误的特殊文件句柄。

STDIN
[ALL] 用于在任何包里做标准输入的特殊文件句柄。

STDOUT
[ALL] 用于在任何包里做标准输出的特殊文件句柄。

$SUBSCRIPT_SEPARATOR
$SUBSEP
$; [ALL] 用于多维散列仿真的下标分隔符。如果你用下面这样的变量引用散列:

$foo{$a, $b, $c}

那么它实际上的意思是:

$foo{join($;, $a, $b, $c)}

但是不要这么写:

@foo{$a, $b, $c} # 一个片段--注意 @

它的意思是:

($foo{$a}, $foo{$b}, $foo{$c})

缺省时是“\034”,和 awk 里的 SUBSEP 一样。请注意如果你的键字包含二进制数据,
那么可能就没有安全的 $;。(记忆方法:逗号——语法上的脚标分隔符——是半个分号。
没错,我们知道这么说相当牵强,不过 $, 已经被更重要的事情占据着了。)

尽管我们还没有废弃这个特性,你现在也应该开始考虑使用“真正”的多维散列了,比如
用 $foo{$a}{$b}{$c} 代替 $foo{$a, $b, $c}。不过,伪(多维)散列可能更容易
排序,并且用做 DBM 文件更容易检查。

$SYSTEM_FD_MAX
$^F
[ALL] 最大“系统”文件描述符,通常是 2。系统文件描述符在一个 exec 过程中传递
给新程序,而更高的文件描述符则不能传递过去。同样,在一个 open 过程中,即使
open 失败也会保留系统文件描述符。(通常文件描述符会在 open 尝试之前关闭,并且
如果 open 失败仍然保持关闭状态。)请注意一个文件描述符的 exec-时关闭的状态将会
在 open 的时候由 $^F 的数值决定,而不是 exec 的时候。我们可以通过临时抬高
$^F 的数值来避免这个现象:

{
local $^F = 10_000;
pipe(HITHER, THITHER) or die "can't pipe:$!";
}

$VERSION
[PKG] 当你声明了一个模块的最小可接受版本的时候,Perl 会访问这个变量,就象
use SomeMod? 2.5 里一样。如果 $SomeMod::VERSION 小于 2.5,那么抛出一个例外。
从技术上来讲,它是查看这个变量的 UNIVERSAL->VERSION 方法,所以,如果你希望非
缺省行为的时候,你可以在当前包里定义你自己的 VERSION 函数。参阅第十二章。

$WARNING
$^W
[ALL] 全局警告开关的当前布尔数值。又见第三十一章,实用模块,里的 use warnings
用法和用于词法范围警告的 -W 和 -X 命令行开关,它们不受这个变量的影响。(记忆
方法:这个变量与 -w 开关有关。)

${^WARNING_BITS}
[NOT,ALL] use warnings 用法打开的当前警告检查设置。参阅第三十一章的
use warnings 获取更多细节。

${^WIDE_SYSTEM_CALLS}
[ALL] 全局标志,在可能的情况下,允许 Perl 做的所有系统调用都使用系统本身的
宽字符 API (wide-character)。你还可以从命令行上用 -C 命令行开关把它打开。
它的初始值通常是 0,主要是为了与早于 5.6 的 Perl 的兼容,但是如果系统提供用户
可设置的缺省(比如通过,$ENV{LC_CTYPE})的时候,可能会自动被 Perl 设置为 1。
use bytes 用法总是在当前词法范围里覆盖这个标记的影响。

现在,让我们拥抱非常大的一章...

<!--

  • Set MYTITLE = 第二十八章,特殊名字

-->