6

system, exec, open '|-',open2等都允许我指定要作为参数列表运行的命令,这些参数将直接传递给execvp而不是通过 shell 运行。

即使perl它看起来像一个“简单”命令时足够聪明,可以直接运行它,这也为我省去了正确地对参数进行外壳转义以及它所带来的所有令人讨厌的陷阱的麻烦。

例子:

open my $out, '|-', $prog, @args;
system $prog, @args;
exec $prog, @args;

代替

open my $out, "|$prog @args";
system "$prog @args";
exec "$prog @args";

qx//运营商有这样的等价物吗?或者你必须总是用手做,例如。

sub slurpcmd {
   open my $h, '-|', @_ or die "open $_[0]|: $!";
   local $/ unless wantarray;
   <$h>
}
4

3 回答 3

5

qx 运算符的列表形式由模块IPC::System::Simple作为函数提供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

在核心中,管道打开在大多数情况下是唯一的选择,除了IPC::Open3类似复杂但也允许引导 STDERR。

于 2019-02-01T22:20:49.860 回答
5

这里有几个简单的选项。

  • 字符串::ShellQuote + qx:

    use String::ShellQuote qw( shell_quote );
    my $cmd = shell_quote(@cmd);
    my $output = `$cmd`;
    
  • IPC::系统::简单

    use IPC::System::Simple qw( capturex );
    my $output = capturex(@cmd)
    
  • IPC::Run3 :

    use IPC::Run3 qw( run3 );
    run3(\@cmd, \undef, \my $output);
    
  • IPC::运行

    use IPC::Run qw( run );
    run(\@cmd, \undef, \my $output);
    

第一个解决方案涉及一个外壳,但没有其他解决方案。

于 2019-02-01T23:21:10.297 回答
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);
    ...

请注意POPpconstxwhich 从堆栈中弹出单个参数以及使用 ofPerlProc_popen而不是PerlProc_popen_list

于 2019-02-03T05:15:24.050 回答