class Proc {}

Proc 是外部进程调用的表示形式。它提供对输入、输出和错误流以及退出代码的访问。它通常通过 run 子例程创建

my $proc = run 'echo''Hallo world':out;
my $captured-output = $proc.out.slurp: :close;
say "Output was $captured-output.raku()";# OUTPUT: «Output was "Hallo world\n"␤» 

管道多个命令也很容易。若要实现 Raku 中管道 echo "Hello, world" | cat -n 的等效项并捕获第二个命令的输出,可以执行

my $p1 = run 'echo''Hello, world':out;
my $p2 = run 'cat''-n':in($p1.out), :out;
say $p2.out.get;

您还可以通过将其设置为 True 直接从程序中馈送 :in(标准输入)管道,这将通过 Proc 上的 .in 方法提供管道

my $p = run "cat""-n":in:out;
$p.in.say: "Hello,\nworld!";
$p.in.close;
say $p.out.slurp: :close;
# OUTPUT: «1  Hello,␤ 
#          2  world!␤» 

为了捕获标准错误,可以提供 :err

my $p = run "ls""-l"".""qqrq":out:err;
my $captured-output = $p.out.slurp: :close;
my $captured-error  = $p.err.slurp: :close;
my $exit-code       = $p.exitcode;

在 sink 上下文中,Proc 将调用其 sink 方法,如果进程以非零退出代码退出,则抛出异常

shell 'exit 1'
# OUTPUT: «(exit code 1) The spawned command 'exit 1' exited unsuccessfully (exit code: 1)␤» 

注意:早于 2017.04 的 Rakudo 版本在 IO::Pipe 对象上没有 .slurp;请改用 .slurp-rest

对非阻塞操作使用 Proc::Async

潜在死锁§

如果您使用 :out:err(因此分别捕获标准输出和标准错误)运行外部程序,则可能会发生死锁,例如在以下情况下

  • 您的 Raku 脚本从程序的标准输出读取,直到文件结束 (EOF) 标记)。

  • 外部程序写入其标准错误流。

  • 外部程序达到其标准错误缓冲区限制。

  • 您的 Raku 脚本阻塞,等待输出流上的输入,而外部程序阻塞,直到其标准错误缓冲区被清空。

您可以通过使用 :merge 加入外部程序的标准输出和错误流来避免这种情况,这样您只需从一个管道读取。这假设您不需要单独访问这两个流。如果您需要,唯一的保存方法是使用 Proc::Async

当您使用 :in 选项(打开到其标准输入的管道)和 :out:err:merge 选项之一调用外部程序时,可能会发生类似的死锁。在这种情况下,可能会发生您的 Raku 脚本阻塞从外部程序的输出读取而等待输入,反之亦然。

在这种情况下,切换到 Proc::Async 是最可靠的解决方案。

方法§

例程 new§

method new(Proc:U:
        :$in = '-',
        :$out = '-',
        :$err = '-',
        Bool :$bin = False,
        Bool :$chomp = True,
        Bool :$merge = False,
        Str:D :$enc = 'UTF-8',
        Str:D :$nl = "\n",
    --> Proc:D)
 
sub shell(
        $cmd,
        :$in = '-',
        :$out = '-',
        :$err = '-',
        Bool :$bin = False,
        Bool :$chomp = True,
        Bool :$merge = False,
        Str:D :$enc = 'UTF-8',
        Str:D :$nl = "\n",
        :$cwd = $*CWD,
        Hash() :$env = %*ENV
    --> Proc:D)

new 创建一个新的 Proc 对象,而 runshell 创建一个对象并使用 @args$cmd 中提供的命令和参数生成它。

$in$out$err 是要启动的程序的三个标准流,默认为 "-",这意味着它们继承父进程的流。将其中一个(或多个)设置为 True 会使流作为同名 IO::Pipe 对象可用,例如 $proc.out。你可以将它们设置为 False 以丢弃它们。或者,你可以传入一个现有的 IO::Handle 对象(例如 IO::Pipe),在这种情况下,此句柄将用于流。

请记住,进程流驻留在进程变量中,而不是使它们可用于我们程序的动态变量中。因此,修改 主机进程中的动态文件句柄变量(例如 $*OUT 不会对生成的进程产生影响,这与 $*CWD$*ENV 不同,它们的更改将实际反映在其中。

my $p-name = "/tmp/program.raku";
my $program = Q:to/END/; 
    #!/usr/bin/env raku
 
    $*OUT.say( qq/\t$*PROGRAM: This goes to standard output/ );
END
 
spurt $p-name$program;
 
$*OUT.put: "1. standard output before doing anything weird";
 
{
    temp $*OUT = open '/tmp/out.txt':w;
    $*OUT.put: "2. temp redefine standard output before this message";
    shell"raku $p-name" ).so;
}
 
$*OUT.put: "3. everything should be back to normal";
# OUTPUT 
# 1. standard output before doing anything weird 
#     /tmp/program.raku: This goes to standard output 
# 3. everything should be back to normal 
 
# /tmp/out.txt will contain: 
# 2. temp redefine standard output before this message 

此程序显示使用 shell 生成的程序未使用主机进程中定义的临时 $*OUT 值(重定向到 /tmp/out.txt),而是进程中定义的初始 STDOUT

$bin 控制流是否作为二进制(即 Blob 对象)或文本(即 Str 对象)处理。如果 $bin 为 False,则 $enc 保存用于对发送到输入流的字符串进行编码和对来自输出和错误流的二进制数据进行解码的字符编码。

$chomp 设置为 True 时,使用 linesget 读取时,会从输出和错误流中删除换行符。$nl 控制你的换行符概念是什么。

如果将 $merge 设置为 True,则标准输出和错误流最终合并到 $proc.out 中。

方法 sink§

method sink(--> Nil)

下沉时,如果 Proc 对象运行的进程退出不成功,则 Proc 对象将抛出 X::Proc::Unsuccessful

shell 'ls /qqq';
# OUTPUT: 
# (exit code 1) ls: cannot access '/qqq': No such file or directory 
# The spawned command 'ls /qqq' exited unsuccessfully (exit code: 2) 
#   in block <unit> at /tmp/3169qXElwq line 1 
# 

方法 spawn§

method spawn(*@args ($*@), :$cwd = $*CWDHash() :$env = %*ENV:$arg0,
             :$win-verbatim-args = False --> Bool:D)

使用给定的命令、参数列表、工作目录和环境运行 Proc 对象。

如果将 :arg0 设置为某个值,则该值将作为 arg0 传递给进程,而不是程序名称。

在 Windows 上,标志 $win-verbatim-args 会禁用所有进程参数的自动引用。有关 Windows 命令引用的更多信息,请参阅 此博客。在所有其他平台上忽略该标志。该标志在 Rakudo 版本 2020.06 中引入,在较旧版本中不存在。

方法 shell§

method shell($cmd:$cwd = $*CWD:$env --> Bool:D)

使用给定的命令和环境运行 Proc 对象,这些命令和环境将通过 shell 进行解析和执行。有关在最常见的操作系统中默认使用哪些 shell 的说明,请参阅 shell

方法命令§

method command(Proc:D: --> List:D)

命令方法是访问器,用于访问包含在通过 spawnshellrun 执行 Proc 对象时传递的参数的列表。

方法 Bool§

multi method Bool(Proc:D:)

等待进程完成,如果进程的退出代码和信号均为 0(表示进程成功终止),则返回 True。否则,返回 False

方法 pid§

method pid()

如果可用,则返回进程的 PID 值,否则返回 Nil

方法 exitcode§

method exitcode(Proc:D: --> Int:D)

返回外部进程的退出代码,如果进程尚未退出,则返回 -1。

方法 signal§

method signal(Proc:D:)

返回外部进程被终止时的信号号,否则返回 0 或未定义的值。

类型图§

Proc 的类型关系
raku-type-graph Proc Proc Any Any Proc->Any Mu Mu Any->Mu

展开上方的图表