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?
答案 0 :(得分:4)
正如在另一个答案中已经指出的那样 - 2>&1
和</dev/null
在同一意义上没有参数,这就是他们不能工作的原因。
然而,就STDIN
和STDERR
而言,您可能希望考虑IPC::Open2
或IPC::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。