具有多个参数的 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】:

这是因为&gt; file.out 是一个shell 功能。通过以您的方式使用system - 您绕过了外壳,并将参数直接提供给您正在调用的程序。

请注意,参数处理取决于参数的数量。如果 LIST 中有多个参数,或者如果 LIST 是一个具有多个值的数组,则以列表的其余部分给出的参数启动列表的第一个元素给出的程序。如果只有一个标量参数,则检查该参数是否有 shell 元字符,如果有,则将整个参数传递给系统的命令 shell 进行解析(在 Unix 平台上是 /bin/sh -c,但在其他平台)。如果参数中没有 shell 元字符,则将其拆分为单词并直接传递给 execvp ,这样效率更高。在 Windows 上,只有系统 PROGRAM LIST 语法才能可靠地避免使用 shell;系统 LIST ,即使有多个元素,如果第一次生成失败,也会退回到 shell。

因此重定向不起作用 - 大概您的程序忽略或以其他方式处理 &gt;file.out 传递的参数。

你可以做一个单行“系统”:

system ( "$cmd @args" );

或使用open 打开文件句柄,并在程序中执行 IO。

【讨论】:

OP 正试图通过避开 shell 来做正确的事情,你建议 system ( "$cmd @args" );?这永远不是答案!

以上是关于具有多个参数的 Perl 系统命令输出到文件的主要内容,如果未能解决你的问题,请参考以下文章

使用系统命令将stdout和stderr输出重定向到文件在perl中不起作用[重复]

将系统命令的输出捕获到文本文件的最佳方法?

Perl在Linux系统下,快速拼接多个文件

在 Perl 中使用 nohup 时如何抑制系统输出?

捕获 Perl 的 'system()' 的输出

如何将linux系统的多个目录及文件备份并压缩到一个文件