将 perl 的 qx{} / `...` 运算符与参数列表一起使用

use perl's qx{} / `...` operator with a list of arguments

systemexecopen '|-'open2 等都允许我将 运行 的命令指定为参数列表将通过 shell.

直接传递给 execvp 而不是 运行

即使 perl 足够聪明,可以直接 运行 如果它看起来像一个 "simple" 命令,那也省去了我正确 shell 转义的麻烦争论及其带来的所有令人讨厌的陷阱。

示例:

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>
}

模块 IPC::System::Simple as the function capturex (additionally like the other functions in that module, it will throw an exception if there is an execution error or non-zero response code, which you can tweak). Alternatively, you can use Capture::Tiny 提供了 qx 运算符的列表形式来包装核心 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。

这里有几个简单的选项。

  • String::ShellQuote + qx:

    use String::ShellQuote qw( shell_quote );
    my $cmd = shell_quote(@cmd);
    my $output = `$cmd`;
    
  • IPC::System::Simple:

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

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

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

第一个解决方案涉及 shell,但其他 none。

事实证明(不幸的是)这并不是我的疏忽——唯一的解决方案确实是使用 open -| 或使用其他答案中列出的外部模块之一。

反引号 implementation(无论是由 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);
    ...

注意 POPpconstx 从堆栈中弹出一个参数,并使用 PerlProc_popen 而不是 PerlProc_popen_list