【问题标题】:use perl's qx{} / `...` operator with a list of arguments使用 perl 的 qx{} / `...` 运算符和参数列表
【发布时间】:2019-02-01 22:17:15
【问题描述】:

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

【问题讨论】:

    标签: perl backticks qx


    【解决方案1】:

    模块IPC::System::Simple作为函数capturex提供了qx运算符的列表形式(此外,与该模块中的其他函数一样,如果执行错误或非零响应,它将抛出异常代码,你可以调整)。或者,您可以使用 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。

    【讨论】:

    • 那些模块不是标准发行版的一部分,对吧?
    • @Căcărău IPC::System::Simple 和 Capture::Tiny 不是核心,但它们是纯 perl,因此可以将 fatpacked 写入脚本。
    • @zdim 它在功能上与 qx 相同,除了它接受参数的方法及其额外的错误处理。并不是暗示它是另一个内置运算符,因为它显然不是。
    【解决方案2】:

    这里有几个简单的选项。

    • 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,但没有其他解决方案。

    【讨论】:

      【解决方案3】:

      事实证明(不幸的是)这不是我的忽视——唯一的解决方案是使用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

      【讨论】:

      • 评论不用于扩展讨论;这个对话是moved to chat。请edit 回答以合并聊天讨论中的任何相关信息。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-26
      • 2014-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多