我有一个需要执行另一个Perl脚本的Perl脚本。第二个脚本可以直接在命令行上执行,但我需要在第一个程序中执行它。我需要传递一些参数,这些参数通常在它独立运行时传递(第一个脚本定期运行,并在一组系统条件下执行第二个脚本)。
初步的Google搜索建议使用反引号或system()调用。有没有其他方法来运行它? (我猜是的,因为它是我们正在讨论的Perl:P)如果我需要从被调用的程序中捕获输出,那么首选哪种方法(如果可能的话,将输出管道输出到stdout,就像第二次一样程序是直接调用的)?
(编辑:哦,现在 SO提出了一些相关的问题。This one很接近,但与我提出的问题并不完全相同。第二个程序可能需要一个小时或更多运行(大量I / O),所以我不确定一次性调用是否适合这种情况。)
答案 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)
我可以想到几种方法来做到这一点。你已经提到了前两个,所以我不会详细介绍它们。
; 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
。
答案 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);