1. 环境变量
可以在一个特定的工作目录下启动进程,然后它会从父进程继承这个工作目录。
在unix类系统上,PATH是以冒号分隔的目录列表,其元素是可执行文件的搜索路径。当输入rm fred
这样的命令时,系统会在目录列表中依次寻找rm
命令
在perl中,环境变量可通过特殊的%ENV
哈希取得。在程序运行时,%ENV
会保留父进程(通常为shell)继承而来的设定值,修改%ENV
这个哈希就可以改变环境变量,它会被perl调用的子进程继承
$ENV{'PATH'} = "/home/rootbeer/bin:$ENV{'PATH'}";
delete $ENV{'IFS'};
my $make_result = system 'make';
use Config;
$ENV{'PATH'} = join $Config{'path_sep'},
'/home/rootbeer/bin', $ENV{'PATH'};
2. exec函数
目前为止,之前介绍的system函数的所有语法也适用于exec函数。不过有一个重要例外,system函数会创建子进程,子进程会在perl睡眠期间执行任务,而exec函数会使当前的perl进程自己去执行任务,有点像“goto”语句执行到一半跑去做别的事,而不是就地调用子程序处理
chdir '/tmp' or die "Cannot chdir /tmp: $!";
exec 'bedrock', '-o', 'args1', @ARGV;
当我们运行到exec时,perl会找到bedrock并且跳进去执行,此后,就没有perl进程了,只有那个执行的bedrock命令的进程。这样在bedrock执行结束时,没有perl进程在等待
这个perl程序的主要功能是为另一个程序的运行设定运行环境。可以预先修改环境变量,修改当前工作目录,修改默认的文件句柄等
$ENV{PATH} = '/bin:/usr/bin';
$ENV{DEBUG} = 1;
$ENV{ROCK = 'granite';
chdir '/Users/fred';
open STDOUT, '>', '/tmp/granite.out';
exec 'bedrock';
如果使用system而不是exec,perl程序就必须傻傻的等另一个程序运行完毕才能跟着收工
不过我们一般很少用到exec,一般都是将exec和fork一起使用
如果不知道该用system还是exec,那就用system好啦
一旦启动了要执行的程序,perl就放手退出,无法再控制它,因此再exec调用之后写的任何代码都无法运行,不过如果启动过程出现错误,那么后续的捕获语句还是可以继续执行的
exec 'date';
die "date couldn't run: $!";
3. 用反引号捕获输出结果
无论用system还是exec,所执行命令的输出都会被重定向到perl的标准输出,不过有时候会想把输出结果捕获成字符串
my $now = `date`; # 捕获date命令的输出
print "The time is now $now"; # 换行符已经包含在捕获内容中
这个像是unix shell的反引号一样,不过shell还会做额外的处理,它会将最后一个换行符移除
chomp(my $no_newline_now = `date`);
print "A moment ago, it was $no_newline_now, I think.\n";
反引号里面的内容就相当于单个参数形式的system函数调用,并且按照双引号内的字符串进行解释
my @functions = qw{ int rand sleep length hex eof not exit sqrt umask };
my %about;
foreach (@functions){
$about{$_} = `perldoc -t -f $_`;
}
除了反引号,还可以使用更为一般化的引起操作符qx(),它所完成的工作和反引号是一样的
foreach (@functions){
$about{$_} = qx(perldoc -t -f $_);
}
和其它一般化的引起操作符类似,选用这种写法可以避免频繁转义带来的干扰。使用引起操作符的另外一个好处是,如果选用单引号作为分隔符的话,可以禁止变量内插
my $output = qx'echo $$';
如果不需要捕获输出内容,就不要使用反引号
print "Starting the frobnitzigator:\n";
`frobnitz -enable`; # 如果要忽略输出结果就没必要这么做
print "Done!\n";
以反引号执行的命令会继承perl当前的标准错误流,如果这个命令将错误信息送到标准错误,就可能会显示在终端上,从而使用户迷糊。
如果想要一起捕获标准输出和标准错误,可以使用shell规范“将标注错误合并至标准输出”,一般在linux中写成 2>&1
my $output_with_errors = `frobnitz -enable 2>&1`;
不过这回让标准错误与标准输出的信息交织在一起。如果需要分别捕获标准输出和标准错误,可以使用模块IPC::Open3
不要用会读取标准输入的命令,如果不太确定这个命令是不是会从标注能输入读取数据,可以将标准输入重定向为从/dev/null
读取数据
my $result = `some_questionable_command arg arg argh </dev/null`; # linux
my $result = `some_questionable_command arg arg argh < NUL`; # windows
Capture::Tiny模块和IPC::System::Simple模块可以封装不同操作系统的特定细节,帮助捕获输出数据