《Perl语言入门》之四——输入与输出

  • 来源:网络
  • 更新日期:2020-08-20

摘要:系统运维 标准输入输出STDIN可以用于接收键盘输入或是文件输入。在标量上下文中执行该操作时,会返回输入中的下一行。while <STDIN> {

系统运维

标准输入输出

STDIN可以用于接收键盘输入或是文件输入。在标量上下文中执行该操作时,会返回输入中的下一行。

while <STDIN> {
    chomp;
    print I saw $_;
}
foreach <STDIN> {
    chomp;
    print;
}

看起来上例中的“while”循环和“foreach”的行为完全一样,其实是有些差别的——在while循环里,Per会读取一行输入,把它存入某个变量并且执行循环的主体,接下来它会回去寻找其他输入行;foreach循环中,行输入操作符会在列表上下文中执行(因为foreach需要逐项处理列表内容),因此Perl会将全部内容读入内存,然后才开始执行循环。当需要处理的输入数据长度很大时,比如处理400M大小的Web服务器日志文件,foreach的效率会比while低很多。因此最好的做法是尽量使用while循环,让它每次处理一行。


钻石操作符的输入<>

钻石操作符提供类似 标准Unix工具程序的参数输入方式,例如对于如下Perl程序“my_program”:

while <> {
    chomp;
    print;
}

如果执行命令“./my_program fred barney betty”,它应该会处理文件fred,接着是barney,最后是betty。(钻石操作符怎么会知道检查命令行参数呢?其实它的参数是来自@ARGV数组)

如果执行命令是没有指定调用参数,程序会从标准输入流采集数据。

当然还有个例外,如果参数中包含连字符“-”,则Perl代码处理到连字符时,会临时改从标准输入读取数据。


使用print/printf/say输出到标准输出

Print操作符会读取后续列表中的所有元素,并把每一项一次送到标准输出。

print <>; #相当于Unix下的cat命令 
print sort <>; #相当于Unix下的sort命令

如果对print的输出格式不够满意,还可以使用printf来产生格式化过的输出结果。

printf Hello, %s; your password expires in %d days!\\n, $user, $days_to_die;

当然Perl一如既往地提供了更方便的格式"%g" (你可以把"g"当成"General"数字转换)。

一般来说,我们编写printf的格式化字符串时已经确定了替换参数的个数和类型,不过万事没有绝对,下面的例子就是用程序在运行时动态产生格式字符串。

my @items = qw( wilma dino pebbles ); 
my $format = The items are: \\n . (%10s\\n x @items); 
printf $format, @items;

另外,有个叫Perl Power Tools (PPT)的项目目标就是用perl重写所有经典Unix工具程序,但是在重写shell的时候陷入了难题。PPT项目一度非常有用,因为它使所有便准的工具程序可以运行在非Unix机器上。

Say函数的功能和print的差不多,但在打印每行内容时都会自动加上换行符。所以下面几种写法的输出结果都一样:

use 5.010 
print Hello!\\n; 
print Hello! . \\n; 
say Hello!;


文件句柄

一般使用全大写字母来命名文件句柄,但是有6个个数文件句柄是Perl保留的——STDIN、STDOUT、STDERR、DATA、ARGV以及ARGVOUT。

open CONFIG, \'dino\'; #打开一个文件 
open CONFIG, \'<dino\' #只读方式打开一个文件 
open REDROCK, \'>fred\' #创建一个新的文件,如果已经存在,则清除原有内容并以新内容代替 
open LOG, \'>>logfile\' #追加方式打开一个文件,如果文件不存在,则创建一个新文件

5.6版的Perl里,加入了open的三个参数的写法:

open CONFIG, \'<\', \'dono\'; 
open BEDROCK, \'>\', $file_name; 
                                                                         
open CONFG, \'<:encoding(UTF-8)\', $file_name; #使用UTF-8编码打开文件,这种书写方式会确认编码是否正确 
open BEDROCK, \'>:utf8\', &logfile_name(); #这种简写的方式不会考虑输入输出的数据是否真的是合法的UTF-8字符串

我们可以通过下面的这条命令打印出说有perl能理解的字符编码清单:

% perl -MEncode -le print for Encode->encodings(\':all\')

除了字符编码之外,数据输入或输出过程中还可以做其他转换操作。比如DOS风格和Unix风格的换行符:

open BEDROCK, \'>:crlf\', $file_name; #按照DOS换行符风格写入文件 
open BEDROCK, \'<:crlf\', $file_name; #读取DOS风格的文件



关闭文件句柄

close BEDROCK;


出错处理

当Perl遇到致命错误时,你的程序应该立刻中止运行,并发出错误信息告知原因。这样的功能可以用die函数来实现。

if ( ! open LOG, \'>>\', \'logfile\' ) { 
    die Cannot create logfile: $!; #die函数会终止程序的运行并打印出错信息 
}

"$!"代表可读的系统错误信息。一般来说,当系统拒绝我们的请求时,"$!"会给出一个解释,类似于C语言中调用perror取得的字符串。

如果Perl遇到的错误是非致命的,可以使用warn函数送出警告信息。warn函数的功能就是产生类似于Perl的内置警告信息的信息(比如启用警告信息时,使用某个undef变量却将它当成已有的值来参与计算,就会触发警告信息)。


自动检测致命错误

从Perl 5.10开始,为人称道的autodie编译指令已经成为标准库的一部分。

use autodie;

这条编译指令是靠判别具体操作的类型来工作的。如果Perl内置函数调用了操作系统接口的话,那么中途出现的错误并不是编程人员所能控制的,所以一旦发现系统调用出错,autodie便会自动帮你调用die。


使用文件句柄

以写入或添加方式打开文件后,可以直接使用print或printf将字符串输出到文件中:

print LOG Captain\'s log, stardate 3.14159; 
printf STDERR %d percent complete.\\n, $done/$total * 100;

如果print/printf的参数列表没有提供文件句柄,则字符串默认被输出到STDOUT。不过可以使用select操作符改变默认的文件句柄,另外还有一个很奇特的变量"$|",当它的值被设为1,就会使当前的默认句柄在每次输出操作后立刻刷新缓冲区。所以,如果要让输出的内容立即显示(比如在读取监视某个耗时程序的实时日志时),应该这么做:

select LOG; # 将默认输出设定为LOG文件句柄 
$|= 1; # 不要将LOG的内容保留在缓冲区 
select STDOUT; 
print LOG This gets written to the LOG at once!\\n;


新网虚拟主机