进程间通信
运行程序
许多程序需要能够运行其他程序,我们需要将信息传递给它们并接收它们的输出和退出状态。在 Raku 中运行程序非常简单:
run 'git', 'status';
这一行运行名为 “git” 的程序,并将 “git” 和 “status” 传递给它的命令行。它将使用 %*ENV<PATH>
设置找到该 git 程序。
如果您想通过向 shell 发送命令行来运行程序,那么也有一个工具。所有 shell 元字符都由 shell 解释,包括管道,重定向,环境变量替换等。
shell 'ls -lR | gzip -9 > ls-lR.gz';
使用 shell
用户输入时应小心。
Proc 对象
run
和 shell
都返回一个PROC对象,它可以使用具有更详细的进程进行通信。请注意,除非您关闭所有输出管道,否则程序通常不会终止。
my $git = run 'git', 'log', '--oneline', :out;
for $git.out.lines -> $line {
my ($sha, $subject) = $line.split: ' ', 2;
say "$subject [$sha]";
}
$git.out.close();
如果程序失败(以非零退出码退出),它将在返回的Proc对象沉没时抛出异常。您可以将其保存为变量,甚至是匿名变量,以防止下沉:
$ = run '/bin/false'; # does not sink the Proc and so does not throw
您可以通过传递 :out
和 :err
标志来告诉 Proc
对象将输出捕获为文件句柄。您也可以通过 :in
标记传递输入。
my $echo = run 'echo', 'Hello, world', :out;
my $cat = run 'cat', '-n', :in($echo.out), :out;
say $cat.out.get;
$cat.out.close();
您还可以使用 Proc
捕获PID,将信号发送到应用程序,并检查 exitcode。
my $crontab = run 'crontab', '-l';
if $crontab.exitcode == 0 {
say 'crontab -l ran ok';
}
else {
say 'something went wrong';
}
Proc::Async 对象
当您需要更多地控制与另一个进程的通信时,您将需要使用Proc::Async。该类提供对与程序进行异步通信的支持,以及向该程序发送信号的能力。
# Get ready to run the program
my $log = Proc::Async.new('tail', '-f', '/var/log/system.log');
$log.stdout.tap(-> $buf { print $buf });
$log.stderr.tap(-> $buf { $*ERR.print($buf) });
# Start the program
my $done = $log.start;
sleep 10;
# Tell the program to stop
$log.kill('QUIT');
# Wait for the program to finish
await $done;
上面的小程序使用“tail”程序每 10 秒打印出名 system.log
的日志内容,然后通过 QUIT 信号告诉程序停止。
虽然 Proc
使用 IO::Handle
提供对输出的访问,但 Proc::Async
使用异步 supplies 提供访问(请参阅Supply)。
如果要在等待原始程序完成时运行程序并执行某些工作,则 start
例程将返回Promise,该程序在程序退出时保留(kept)。
使用 write
方法将数据传递到程序中。