system,exec,open '|-',open2,等方面都让我来指定作为将直接传递到参数列表运行命令execvp通过一个外壳,而不是运行.
即使perl它足够聪明,如果它看起来像一个"简单"的命令,它可以直接运行它,这样可以省去正确的shell转义所带来的所有令人讨厌的陷阱的麻烦.
例:
open my $out, '|-', $prog, @args;
system $prog, @args;
exec $prog, @args;
Run Code Online (Sandbox Code Playgroud)
代替
open my $out, "|$prog @args";
system "$prog @args";
exec "$prog @args";
Run Code Online (Sandbox Code Playgroud)
qx//运营商是否有这样的等价物?或者你必须总是手工完成,例如.
sub slurpcmd {
open my $h, '-|', @_ or die "open $_[0]|: $!";
local $/ unless wantarray;
<$h>
}
Run Code Online (Sandbox Code Playgroud)
的操作者QX的列表形式由模块提供IPC ::系统::简单的函数capturex(另外像模块中的其他功能,如果存在一个执行错误或非零响应代码将抛出异常,你可以调整).或者,您可以使用Capture :: Tiny来包装核心system调用并提供相同的行为,但它也有其他功能可以将STDERR包装在一起或与STDOUT分开.
use strict;
use warnings;
use IPC::System::Simple 'capturex';
my $output = capturex $prog, @args;
use Capture::Tiny 'capture_stdout';
my ($output, $exit) = capture_stdout { system $prog, @args };
# standard system() error checking required here
Run Code Online (Sandbox Code Playgroud)
在核心中,管道打开在很大程度上是唯一的选择,除了IPC :: Open3,它同样复杂但也允许指向STDERR.
这里有一些简单的选择.
String :: ShellQuote + qx:
use String::ShellQuote qw( shell_quote );
my $cmd = shell_quote(@cmd);
my $output = `$cmd`;
Run Code Online (Sandbox Code Playgroud)use IPC::System::Simple qw( capturex );
my $output = capturex(@cmd)
Run Code Online (Sandbox Code Playgroud)use IPC::Run3 qw( run3 );
run3(\@cmd, \undef, \my $output);
Run Code Online (Sandbox Code Playgroud)use IPC::Run qw( run );
run(\@cmd, \undef, \my $output);
Run Code Online (Sandbox Code Playgroud)第一个解决方案涉及一个shell,但没有其他解决方案.
小智 1
事实证明(不幸的是)这并不是我的疏忽——唯一的解决方案实际上是使用open -|其他答案中列出的外部模块之一来实现这一点。
反引号实现(无论是由qx/.../、`...`或调用readpipe)是深入硬连线以接受单个字符串参数:
PP(pp_backtick)
{
dSP; dTARGET;
PerlIO *fp;
const char * const tmps = POPpconstx;
const U8 gimme = GIMME_V;
const char *mode = "r";
TAINT_PROPER("``");
if (PL_op->op_private & OPpOPEN_IN_RAW)
mode = "rb";
else if (PL_op->op_private & OPpOPEN_IN_CRLF)
mode = "rt";
fp = PerlProc_popen(tmps, mode);
...
Run Code Online (Sandbox Code Playgroud)
请注意,它POPpconstx从堆栈中弹出单个参数,并使用PerlProc_popen代替PerlProc_popen_list。