好的错误信息是有用的,因为它们告诉我们,当出错时,我们不必检查什么。(见:LTA)我通过尝试用 Raku 替换 Bash 得出了这个结论。让我们来看看一些无辜的代码。
my $p = Proc.new;
$p.spawn(<does-not-exist>);
$p.sink;
CATCH {
default { say .^name, ‚: ‘, .message; .resume }
}
# OUTPUT: «X::Proc::Unsuccessful: The spawned command 'does-not-exist' exited unsuccessfully (exit code: 1, signal: 0)»
这个错误信息是错误的。一个由 exec
运行和派生的命令,只有当可执行文件或脚本是可执行的,对于操作系统用户可访问的,一个正常的文件,而不是一个目录,才能产生一个非零的退出代码。(还有更多,但这些因操作系统而异。)正如命令的名字所暗示的那样,它不存在,因此不能产生1的退出码。 这一点我炮制了 brtfs 来创建一个快照。因为 brtfs 不是一个有效的命令。这是一个拼写错误。当我终于意识到 btrfs 的效果要好得多时,15分钟已经过去了。许多 unix 命令会根据提供的参数产生不同的错误代码。所以当需要使用重度 shell 脚本时,这种拼写错误真的会让人很困惑。
上面的例子是 Proc::*
产生异常的唯一方法。这就很麻烦了,因为语言使用者并不是要手工创建一个 Proc
对象。子程序 run
、shell
和 qx{}
永远不会在 sink 上下文 中使用它。相反,它们会在检查错误时评估为 False。我们可以像许多 shell 语言一样,通过用 &&
这样的方式链住命令来模仿 shell 脚本。然而,$shell
会检查 errno
,并说明 “命令未找到"以帮助用户。Rakudo 却没有这样做。我们可以通过几行代码来改变这一点。
class X::Proc::CommandNotFound is X::Proc::Unsuccessful {
method message {
my $symlink = $.proc.command[0].IO.l ?? ' (symlink)' !! '';
"The command '{$.proc.command[0]}'$symlink was not found."
}
}
sub use-proc-fatal {
&run.wrap(-> |c {
my Proc:D $ret := callsame;
if $ret.exitcode > 0 {
with $ret.command[0].IO {
X::Proc::CommandNotFound.new(:proc($ret)).throw unless .e;
}
X::Proc::Unsuccessful.new(:proc($ret)).throw if $ret.exitcode > 0 || $ret.signal > 0;
}
$ret
});
}
use-proc-fatal;
say ‚### run does-not-exist‘;
run 'does-not-exist';
CATCH {
default { say .^name, ‚: ‘, .message; }
}
run does-not-exist
X::Proc::CommandNotFound: The command 'does-not-exist' was not found.
这不是一个正确的解决方案。首先,Proc
永远不应该抛出异常。如果有的话,Raku 应该失败,因为它和 //
一起比较好。在 shell 脚本中,命令的执行不成功是很正常的。错误处理只是游戏的一部分。既然它如此常见,就应该有更多更好的异常。我有一个脚本,我多测试了几种情况,多了一些异常。让这些从运行和 shell 中返回的是 Failure,会让 qx
不再默默地失败。
在我的备份脚本中,我必须将每个命令都包在一个 sub 中,并抛出异常,以利用 CATCH
和 LEAVE
块进行错误处理和清理(有临时目录 /file
和 btrfs 快照)。我真的希望在核心中能有一个使用 Proc::Fatal
来帮助完成这个任务。我相信这需要在核心中,因为 errno
隐藏在 Proc
里面,在 Proc::Async
里面,在 nqp::spawnprocasync
里面,在 MVM_proc_spawn_async
里面,我在那里停了下来,又爬回了兔子洞。事实上我一直没有找到那个该死的 exec*
。另外 Bash 在大约50行代码之后就不再好玩了。简单的事情应该是简单的。
我很确定我错过了很多错误模式。所以这需要进一步的思考。如果你有这样的请分享。如果你现在写一篇关于 Raku 的博文,你可以期待一周500次点击。这比去年增长了20%。我们比股市还要好! 在这个世界上,钱可以印,但工作不能印,这是一个真正的壮举。
by gfldex