如何在Perl脚本中运行Perl脚本?

时间:2008-12-13 04:34:18

标签: perl ipc

我有一个需要执行另一个Perl脚本的Perl脚本。第二个脚本可以直接在命令行上执行,但我需要在第一个程序中执行它。我需要传递一些参数,这些参数通常在它独立运行时传递(第一个脚本定期运行,并在一组系统条件下执行第二个脚本)。

初步的Google搜索建议使用反引号或system()调用。有没有其他方法来运行它? (我猜是的,因为它是我们正在讨论的Perl:P)如果我需要从被调用的程序中捕获输出,那么首选哪种方法(如果可能的话,将输出管道输出到stdout,就像第二次一样程序是直接调用的)?

(编辑:哦,现在 SO提出了一些相关的问题。This one很接近,但与我提出的问题并不完全相同。第二个程序可能需要一个小时或更多运行(大量I / O),所以我不确定一次性调用是否适合这种情况。)

9 个答案:

答案 0 :(得分:32)

你可以它。

{
    local @ARGV = qw<param1 param2 param3>;
    do '/home/buddy/myscript.pl';
}

防止在另一个perl副本中加载的开销。

答案 1 :(得分:30)

您当前的perl解释器的位置可以在特殊变量$^X中找到。如果perl不在您的路径中,或者您有多个perl版本可用但确保您使用相同的perl版本,这一点非常重要。

执行外部命令(包括其他Perl程序)时,确定它们是否实际运行可能非常困难。检查$?会留下持久的精神伤疤,所以我更喜欢使用IPC::System::Simple(可从CPAN获得):

use strict;
use warnings;
use IPC::System::Simple qw(system capture);

# Run a command, wait until it finishes, and make sure it works.
# Output from this program goes directly to STDOUT, and it can take input
# from your STDIN if required.
system($^X, "yourscript.pl", @ARGS);

# Run a command, wait until it finishes, and make sure it works.
# The output of this command is captured into $results.
my $results = capture($^X, "yourscript.pl", @ARGS);

在上述两个示例中,您希望传递给外部程序的任何参数都会转到@ARGS。在上述两个示例中也避免使用shell,这样可以提供较小的速度优势,并避免涉及shell元字符的任何不需要的交互。上面的代码还希望你的第二个程序返回一个零退出值来表示成功;如果不是这种情况,您可以指定允许退出值的附加第一个参数:

 # Both of these commands allow an exit value of 0, 1 or 2 to be considered
 # a successful execution of the command.

 system( [0,1,2], $^X, "yourscript.pl", @ARGS );
 # OR
 capture( [0,1,2, $^X, "yourscript.pl", @ARGS );

如果您有一个长时间运行的进程并且想要在生成时处理其数据,那么您可能需要管道打开,或者一个更重量级的IPC模块来自CPAN。

说了这么多,每当你需要从Perl调用另一个Perl程序时,你可能希望考虑使用模块是否是更好的选择。启动另一个程序会带来相当多的开销,包括启动成本和在进程之间移动数据的I / O成本。它还显着增加了错误处理的难度。如果您可以将外部程序转换为模块,您可能会发现它简化了整体设计。

一切顺利,

答案 2 :(得分:12)

你已经对你的问题得到了很好的答案,但总是有可能采取不同的观点:也许你应该考虑重构你想从第一个脚本运行的脚本。将功能转换为模块。使用第一个和第二个脚本中的模块。

答案 3 :(得分:11)

我可以想到几种方法来做到这一点。你已经提到了前两个,所以我不会详细介绍它们。

  1. 反引号:$ retVal =``perl somePerlScript.pl ;
  2. system()调用
  3. EVAL
  4. eval可以通过将另一个文件啜饮成字符串(或字符串列表)来完成,然后'评估'字符串。下面是一个样本:

    #!/usr/bin/perl
    open PERLFILE, "<somePerlScript.pl";
    undef $/;   # this allows me to slurp the file, ignoring newlines
    my $program = <PERLFILE>;
    eval $program;
    

    4。执行:

    do 'somePerlScript.pl'

答案 4 :(得分:6)

如果需要捕获命令的输出,请使用反引号。

如果您不需要捕获命令的输出,请使用system

TMTOWTDI:所以还有其他方法,但这两种方式最简单,最有可能。

答案 5 :(得分:6)

如果您需要异步调用外部脚本 - 您只想启动它而不是等待它完成 - 那么:

# On Unix systems, either of these will execute and just carry-on
# You can't collect output that way
`myscript.pl &`;
system ('myscript.pl &');    

# On Windows systems the equivalent would be
`start myscript.pl`;
system ('start myscript.pl');

# If you just want to execute another script and terminate the current one
exec ('myscript.pl');

答案 6 :(得分:5)

有关进程间通信的几个选项,请参阅perlipc文档。

如果您的第一个脚本仅为第二个脚本设置环境,那么您可能正在寻找exec

答案 7 :(得分:1)

#!/usr/bin/perl
use strict;

open(OUTPUT, "date|") or die "Failed to create process: $!\n";

while (<OUTPUT>)
{
  print;
}

close(OUTPUT);

print "Process exited with value " . ($? >> 8) . "\n";

这将启动进程date并将命令的输出传递给OUTPUT文件句柄,您可以一次处理一行。命令完成后,您可以关闭输出文件句柄并检索进程的返回值。用你想要的任何东西替换date

答案 8 :(得分:0)

我想做这样的事情,将非子程序卸载到外部文件中,以便于编辑。我实际上把它变成了一个子程序。这种方式的优点是外部文件中的那些“我的”变量在主命名空间中声明。如果你使用'do',他们显然不会迁移到主命名空间。请注意,下面的演示文稿不包括错误处理

sub getcode($) {
  my @list;
  my $filename = shift;
  open (INFILE, "< $filename");
  @list = <INFILE>;
  close (INFILE);
  return \@list;
}

# and to use it:

my $codelist = [];
$codelist = getcode('sourcefile.pl');
eval join ("", @$codelist);