Overview

有很多时候,我们需要在perl脚本中调用系统命令,比如调用系统的某个软件做一件事。也可以说是在perl脚本中调用外部命令,比如在一个perl脚本中调用另一个perl脚本。

有很多种方式可以实现这个目的,这里我列出来3中常见的方式,并以一个例子说明这三种方式的不同之处。

1. 被调用的perl脚本

我们在一个perl脚本(取名为testSystemCall.pl)中调用另一个脚本(取名为printCallInfo.pl)。printCallInfo.pl中内容如下:

#!/usr/bin/perl -w

# usage: perl printCallInfo.pl number
# number: an Integer

use strict;
use warnings;

my $countNumber = $ARGV[0] or die "Need to input an integer on the command line\n";
print "This perl script is called $countNumber times\n";

使用方法已经在脚本中说明,比如使用:

perl printCallInfo.pl 5

屏幕上就会显示:

This perl script is called 5 times

2. 调用脚本testSystemCall.pl

我们在脚本中分别查看使用以下三种方式调用printCallInfo.pl

  • system("command");
  • exec("command");
  • `command`;

testSystemCall.pl脚本内容如下:

#!/usr/bin/perl -w

# usage: perl testSystemcall.pl number
# number : an enum number
#        1: use system("command")
#        2: use exec("command")
#        3: use `command`;

use strict;
use warnings;

my $exceType = $ARGV[0] or die "Need to input an integer(1,2,3) on the command line\n";

print "Begin loop to invoke system call: \n";
for(my $i=1; $i<=5;$i++)
{

    ($exceType == 1) and system("perl printCallInfo.pl $i");
    ($exceType == 2) and exec("perl printCallInfo.pl $i");
    ($exceType == 3) and `perl printCallInfo.pl $i`;
}
print "End loop.\n";

这个脚本需要指定一个1或者2或者3的整数,指定1代表执行system("perl printCallInfo.pl $i"),指定2或者3以此类推。

这里注意orand的使用,也可以分别使用||&&代替。巧妙使用这种方式可以节省很多if else语句。

2.1 system("command") (推荐)

使用该命令将开启一个子进程执行引号中的命令,父进程将等待子进程结束并继续执行下面的代码。

使用命令:

perl testSystemCall.pl 1

执行了system("perl printCallInfo.pl $i");,得到下面的结果:

Begin loop to invoke system call:
This perl script is called 1 times
This perl script is called 2 times
This perl script is called 3 times
This perl script is called 4 times
This perl script is called 5 times
End loop.

结果在意料之中。

2.2 exec("command");

效果同system命令类似,区别是不会开启子进程,而是取代父进程,因此执行完引号中的命令后进程即结束。一般和fork配合使用。

使用命令:

perl testSystemCall.pl 2

执行了exec("perl printCallInfo.pl $i");,得到下面的结果:

Begin loop to invoke system call:
This perl script is called 1 times

结果出乎意料,如果你刚才还不太理解这一小节引用的那句话,现在应该明白了。exec命令取代了父进程,执行一次结束之后进程结束,因为这个进程就是父进程本身,因此父进程也跟着结束了。testSystemCall.pl脚本中的后续内容也就不会执行了。

3. `command`

使用反引号调用外部命令能够捕获其标准输出,并按行返回且每行结束处附带一个回车。反引号中的变量在编译时会被内插为其值。

好像更不好理解了。先执行一下:

perl testSystemCall.pl 3

执行了`perl printCallInfo.pl $i`;这句代码,显示如下:

Begin loop to invoke system call:
End loop.

什么都没打印,好像没执行一样。其实已经执行了,只是`perl printCallInfo.pl $i`没有把printCallInfo.pl中的输出直接输出到屏幕上,而是返回给了testSystemCall.pl,只是我们在testSystemCall.pl中并没有接收这个返回值。

我们修改一下testSystemCall.pl,将

($exceType == 3) and `perl printCallInfo.pl $i`;

改成:

($exceType == 3) and print `perl printCallInfo.pl $i`;

我们将`perl printCallInfo.pl $i`返回的内容再重新打印出来,重新执行:

perl testSystemCall.pl 3

显示如下:

Begin loop to invoke system call:
This perl script is called 1 times
This perl script is called 2 times
This perl script is called 3 times
This perl script is called 4 times
This perl script is called 5 times
End loop.

显示内容是不是更符合我们的期望了~

3. 参考资料