open:使用数组作为参数时重定向不起作用?

时间:2015-05-07 15:11:15

标签: perl

my $cmd = "$exe build 2>&1 </dev/null";
my $FH = FileHandle->new;
open $FH, '-|', $cmd
    or die "cannot open: $!";
close $FH;

现在我将$ cmd更改为数组

my @cmd = ($exe, 'fly', '2>&1', '</dev/null');

似乎忽略了'2>&1'和'</dev/null'

如何使用open的参数保留重定向STDIN和STDERR?

3 个答案:

答案 0 :(得分:4)

正如在另一个答案中已经指出的那样 - 2>&1</dev/null在同一意义上没有参数,这就是他们不能工作的原因。

然而,就STDINSTDERR而言,您可能希望考虑IPC::Open2IPC::Open3 - 这样您就不必担心它。

use IPC::Open3;
$pid = open3(my $exe_stdin, my $exe_stdout, my $exec_stderr,
                'some cmd and args', 'optarg', ...);

这样您只需close $exe_stdin即可获得与重定向/dev/null相同的结果,您可以独立阅读其他流。

答案 1 :(得分:3)

当只有一个参数时,它被视为shell命令。

当存在多个时,它被视为执行程序和该程序的参数。

这意味着您以前传递给shell的2>&1现在作为参数传递给程序。

这很容易使用system来演示,它使用相同的约定。

$ perl -e'system(q{perl -E'\''say for @ARGV'\'' abc 2>&1})'
abc

$ perl -e'system(q{perl}, q{-E}, q{say for @ARGV}, q{abc}, q{2>&1})'
abc
2>&1

由于

my $full_cmd = "$exe build 2>&1 </dev/null";

相当于

my @full_cmd = ('sh', '-c', "$exe build 2>&1 </dev/null");

然后我们想要

my @cmd = ($exe, 'build');
my @full_cmd = ('sh', '-c', '"$@" </dev/null', '-', @cmd);

如果我们想要从非shell部分开始。

在上下文中,这意味着要改变

my $cmd = "$exe build 2>&1 </dev/null";
open(my $FH, '-|', $cmd)
   or die("Can't launch $exe: $!\n");

my @cmd = ($exe, 'build');
open(my $FH, '-|', 'sh', '-c', '"$@" 2>&1 </dev/null', '-', @cmd)
   or die("Can't launch $cmd[0]: $!\n");

请注意,您还可以使用以下内容:

use String::ShellQuote qw( shell_quote );

my @cmd = ($exe, 'build');
open(my $FH, '-|', shell_quote(@cmd).' 2>&1 </dev/null')
   or die("Can't launch $cmd[0]: $!\n");

答案 2 :(得分:2)

您尝试使用的模式open FILEHANDLE, MODE, EXPR, LIST包含以下注释:

  

以管道打开的形式接受三个或更多参数,如果指定了LIST(命令名后面的额外参数),那么LIST将成为在平台支持时调用的命令的参数。

但是,使用2>&1</dev/null的重定向是 shell构造,而不是参数

如果必须使用数组路径,则需要使用join重新组合数组元素以符合标准open FILEHANDLE, MODE, EXPR模式。

open $FH, q{-|}, join(' ', @cmd)

注意:如果您使用数组来避免$exe的shell插值,那么您应该考虑使用IPC::Open3代替@Sobrique's answer