如何在Perl中运行shell命令,就像Raku一样?



我在 Raku 中有很好的代码:

#!/usr/bin/env perl6
CONTROL {
when CX::Warn {
note $_;
die
}
}
use fatal;
role KeyRequired {
method AT-KEY (key) {
die "Key {key} not found" unless self.EXISTS-KEY(key);
nextsame
}
}
sub execute ($cmd) {
put $cmd;
my $proc = shell $cmd, :err, :out;
if $proc.exitcode != 0 {
put 'exit code = ' ~ $proc.exitcode;
put 'stderr ' ~ $proc.err.slurp;
put 'stdout ' ~ $proc.out.slurp;
die
}
}
execute "ls *.p6"

我说"优秀"是因为 Raku 版本运行命令,返回退出代码,并在需要时打印 stdout/stderr,并且所有这些都以易于阅读和易于理解的方式进行。

通读 Perl5 手册IPC::Runhttps://metacpan.org/pod/IPC::Run 我遇到了似乎是最好的 Perl5 方法,但我发现那里使用的方法比 Raku 做事方式更不容易阅读和理解。

通读手册以了解我能找到IPC::Run最好的是:

#!/usr/bin/env perl
use strict;
use warnings FATAL => 'all';
use feature 'say';
use autodie qw(:all);
use IPC::Run qw(run timeout);
sub execute {
my $cmd = shift;
my @cat = ('cat', __FILE__); # Raku doesn't need to split the string into an array
run @cat, undef, my $out, my $err, timeout( 10 ) or die "cat: $?"; 
if ($out ne '') {
say "$out = $out";
}
if ($err ne '') {
say "$err = $err";
}
}
execute("cat " . __FILE__);
execute("cat __Fle");  #intentionally wrong to produce an error

如何重写 Perl5,使其像 Raku 代码一样易于阅读和使用?

你不公平地加载了 Perl 5 示例,有很多额外的绒毛,而且你没有在 Raku 代码中处理很多事情。例如,不管变量中有什么,你都会在 Raku 中输出结果,但在 Perl 5 中测试变量。

你的 Perl 5 看起来更像这样:

use v5.30;
use IPC::Run qw(run timeout);
sub execute {
my @command = @_;
run @command, undef, my $out, my $err, timeout( 10 ) 
or die "cat: $?"; 
say "$out = $out";
say "$err = $err";
}
execute("cat ", __FILE__);

池上在他的 pastebin 链接中提供了这个版本:

sub execute {
my ($command) = @_;
if (! run $command, undef, my $out, my $err, timeout( 10 ) ) {
say "exit code = $?";
say "stderr $err";
put "stdout $out";
die "Died";
}
}

在这两种情况下,都有一件有趣的事情需要注意。如果退出代码不为零,则假设错误(Raku 假设这一点,这就是为什么您必须担心不会使结果下沉的原因(。但是,许多有用的程序不遵循该约定。例如,git merge base使用退出值 1 表示"不是祖先",使用所有大于 1 的退出值表示错误。命令行grep类似。Sendmail 的退出代码为 75,表示某些事情没有解决,但它稍后会重试。

Raku对此有意见,忽略了这种事情,并且不允许你告诉Proc它应该接受哪些退出值作为成功退出。Perl 5 不是那么固执己见。使用or die! ...实际上是在说"退出代码不为零",但这实际上不是一个足够好的描述。在很多情况下,你可以侥幸逃脱,但至少 Perl 5 不会为你做决定。如果您展开 Raku 示例以检查文本值并确定是否成功,它看起来会很混乱。


但是,请注意,Raku的shell文档指出它是不安全的,您应该改用run

就其价值而言,我不认为 Raku 的进程间通信值得信赖。在许多情况下,我认为它的IPC设计被忽视了。例如,请参阅 Perl 6 的 $*OUT 是否会更改子进程的标准输出?我在错误报告和Stackoverflow中还有其他几个IPC问题,几乎没有一个得到满意的答案。大多数情况下,我认为这是因为没有人考虑那么多。当然,Raku是由一个小团队开发的,这是一个大项目,但是当涉及到生产编程时,这不是一个因素。

更多乐壳怪异:

  • Perl 6 的 shell(( 使用哪个 shell?

相关内容

最新更新