具有多个参数的 Perl 系统命令输出到文件
Posted
技术标签:
【中文标题】具有多个参数的 Perl 系统命令输出到文件【英文标题】:Perl system command with multiple parameters output to file 【发布时间】:2016-11-07 16:01:15 【问题描述】:我需要使用以下形式调用系统命令:
system( $cmd, @args );
当我将@args 定义为
my @args = ( "input1", "input2", ">", "file.out" );
“>”和“file.out”没有像我希望的那样被解释。如何将这种形式的系统命令的输出发送到文件?
【问题讨论】:
【参考方案1】:这将四个参数传递给程序,就好像您在 shell 中执行了以下内容:
prog "input1" "input2" ">" "file.out"
你不能在不使用 shell 的情况下指示 shell 重定向输出!
以下解决方案假设:
my $prog = 'cat';
my @args = ( 'input1', 'input2' );
my $out_qfn = 'file.out';
以下解决方案都缺少一些错误检查。
解决方案 1
使用 shell 执行重定向和转义。
system('/bin/sh', '-c', '"$@" > "$0"', $out_qfn, $prog, @args);
解决方案 2
使用shell进行重定向,使用Perl进行转义。
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote($prog, @args) . " >".shell_quote($out_qfn);
system('/bin/sh', '-c', $cmd);
最后一行简化为
system($cmd);
解决方案 3
避免使用外壳。使用 Perl 执行重定向。
# This isn't safe if @args is empty.
open(my $out_fh, '>', $out_qfn)
or die("Can't create output file \"$out_qfn\": $!\n");
open(my $pipe, '-|', $prog, @args)
or die $!;
while (<$pipe>)
print($out_fh $_);
close($fh);
或
# This isn't safe if @args is empty.
use IPC::Open3 qw( open3 );
open(local *CHILD_STDIN, '<', '/dev/null')
or die $!;
open(local *CHILD_STDOUT, '>', $out_qfn)
or die("Can't create output file \"$out_qfn\": $!\n");
my $pid = open3('<&CHILD_STDIN', '>&CHILD_STDOUT', '>&STDERR', $prog, @args);
waitpid($pid, 0);
或
use IPC::Run3 qw( run3 );
run3([ $prog, @args ], \undef, $out_qfn);
或
use IPC::Run qw( run );
run([ $prog, @args ], \undef, $out_qfn);
【讨论】:
【参考方案2】:这是因为> file.out
是一个shell 功能。通过以您的方式使用system
- 您绕过了外壳,并将参数直接提供给您正在调用的程序。
请注意,参数处理取决于参数的数量。如果 LIST 中有多个参数,或者如果 LIST 是一个具有多个值的数组,则以列表的其余部分给出的参数启动列表的第一个元素给出的程序。如果只有一个标量参数,则检查该参数是否有 shell 元字符,如果有,则将整个参数传递给系统的命令 shell 进行解析(在 Unix 平台上是 /bin/sh -c,但在其他平台)。如果参数中没有 shell 元字符,则将其拆分为单词并直接传递给 execvp ,这样效率更高。在 Windows 上,只有系统 PROGRAM LIST 语法才能可靠地避免使用 shell;系统 LIST ,即使有多个元素,如果第一次生成失败,也会退回到 shell。
因此重定向不起作用 - 大概您的程序忽略或以其他方式处理 >
和 file.out
传递的参数。
你可以做一个单行“系统”:
system ( "$cmd @args" );
或使用open
打开文件句柄,并在程序中执行 IO。
【讨论】:
OP 正试图通过避开 shell 来做正确的事情,你建议system ( "$cmd @args" );
?这永远不是答案!以上是关于具有多个参数的 Perl 系统命令输出到文件的主要内容,如果未能解决你的问题,请参考以下文章