如何存储run或shell返回的值?

时间:2018-12-31 04:32:35

标签: perl6 raku

假设我有这个脚本:

# prog.p6
my $info = run "uname";

运行prog.p6时,我得到:

$ perl6 prog.p6
Linux

是否有一种方法可以存储返回值的字符串化版本,并防止将其输出到终端?

已经有一个similar question,但没有提供具体答案。

3 个答案:

答案 0 :(得分:8)

您需要通过设置$*OUT启用标准输出管道,否则默认为:out。所以:

my $proc = run("uname", :out);
my $stdout = $proc.out;
say $stdout.slurp;
$stdout.close;

可以缩写为:

my $proc = run("uname", :out);
say $proc.out.slurp(:close);

如果要在stderr上捕获输出而不是在stdout上捕获输出,可以执行以下操作:

my $proc = run("uname", :out, :err);
say "[stdout] " ~ $proc.out.slurp(:close);
say "[stderr] " ~ $proc.err.slurp(:close);

或者如果要将stdout和stderr捕获到一个管道中,则:

my $proc = run("uname", :merge);
say "[stdout and stderr] " ~ $proc.out.slurp(:close);

最后,如果您不想捕获输出并且不希望将其输出到终端:

my $proc = run("uname", :!out, :!err);
exit( $proc.exitcode );

答案 1 :(得分:4)

此答案涵盖的解决方案很简洁。

有时候,它的弊端大于其缺点:

  • 不存储结果代码。如果需要,请改用ugexe解决方案。

  • 不将输出存储到stderr。如果需要,请改用ugexe解决方案。

  • 潜在漏洞。下面对此进行说明。请考虑使用ugexe的解决方案。


下面说明的功能文档以the quote adverb :exec开始。

最不安全的变体:q

最安全的变体使用单个q

say qx[ echo 42 ] # 42

如果出现错误,则构造返回一个空字符串,并且任何错误消息都将出现在stderr上。

此最安全的变体类似于传递给shell的带引号的字符串,例如'foo'。单引号字符串不interpolate,因此code injection attack没有漏洞。

也就是说,您要向外壳传递单个字符串,而该外壳可能不是您期望的外壳,因此它可能无法按您期望的那样解析字符串。

不安全的不安全变体:qq

以下行产生与q行相同的结果,但使用的是最不安全的变体:

say qqx[ echo 42 ]

此双q变体类似于双引号字符串("foo")。这种形式的字符串引用 does 是插值的,这意味着如果您在传递给shell的字符串中包含变量,则它受code injection attack约束。

答案 2 :(得分:4)

默认情况下,run仅将STDOUTSTDERR传递到父进程的STDOUTSTDERR

您必须告诉它做其他事情。

最简单的方法是只给它:out,告诉它保留STDOUT。 (:out(True)的缩写)

my $proc = run 'uname', :out;
my $result = $proc.out.slurp(:close);
my $proc = run 'uname', :out;
for $proc.out.lines(:close) {
  .say;
}

您还可以有效地告诉它仅将STDOUT发送到/dev/null:!out。 (:out(False)的缩写)


:out可以做更多的事情

{
  my $file will leave {.close} = open :w, 'test.out';
  run 'uname', :out($file); # write directly to a file
}

print slurp 'test.out'; # Linux
my $proc = run 'uname', :out;

react {
  whenever $proc.out.Supply {
    .print

    LAST {
      $proc.out.close;
      done; # in case there are other whenevers
    }
  }
}

如果您要执行最后一个操作,最好使用Proc :: Async。