IPC::Open3 - 使用 open3() 打开一个进程以进行读取、写入和错误处理
use Symbol 'gensym'; # vivify a separate handle for STDERR
my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
'some', 'cmd', 'and', 'args');
# or pass the command through the shell
my $pid = open3(my $chld_in, my $chld_out, my $chld_err = gensym,
'some cmd and args');
# read from parent STDIN
# send STDOUT and STDERR to already open handle
open my $outfile, '>>', 'output.txt' or die "open failed: $!";
my $pid = open3('<&STDIN', $outfile, undef,
'some', 'cmd', 'and', 'args');
# write to parent STDOUT and STDERR
my $pid = open3(my $chld_in, '>&STDOUT', '>&STDERR',
'some', 'cmd', 'and', 'args');
# reap zombie and retrieve exit status
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;
与 open2() 极其类似,open3() 会生成给定的命令并连接 $chld_out 以从子进程读取,连接 $chld_in 以写入子进程,连接 $chld_err 以处理错误。如果 $chld_err 为 false 或与 $chld_out 为同一文件描述符,则子进程的 STDOUT 和 STDERR 位于同一文件句柄上。这意味着无法对 STDERR 文件句柄使用自动生成的词法作用域,但可以从 Symbol 中使用 gensym 生成新的全局引用,请参见 "语法"。$chld_in 将启用自动刷新。
如果 $chld_in 以 <&
开头,则 $chld_in 将在父进程中关闭,并且子进程将直接从中读取。如果 $chld_out 或 $chld_err 以 >&
开头,则子进程将直接向该文件句柄发送输出。在这两种情况下,都会进行 dup(2),而不是 pipe(2)。
如果读取器或写入器为空字符串或未定义,则将用自动生成的文件句柄替换它。如果是这样,则必须在参数槽中传递一个有效左值,以便可以在调用方中覆盖它,否则将引发异常。
文件句柄也可以是整数,在这种情况下,它们被理解为文件描述符。
open3() 返回子进程的进程 ID。它不会在发生故障时返回:它只会引发与 /^open3:/
匹配的异常。但是,子进程中的 exec
故障(例如没有此类文件或拒绝访问)仅在 Windows 和 OS/2 下报告给 $chld_err,因为无法捕获它们。
如果子进程因任何原因而终止,则下一次对 $chld_in 的写入可能会在父进程中生成一个 SIGPIPE,而这在默认情况下是致命的。因此,您可能希望处理此信号。
请注意,如果您指定 -
作为命令,类似于 open(my $fh, "-|")
,则子进程将只是派生的 Perl 进程,而不是外部命令。此功能在 Win32 平台上尚不受支持。
open3() 不会在子进程退出后等待并回收它。对于允许操作系统处理此问题的短程序除外,您需要自己执行此操作。这通常与在您完成进程时调用 waitpid $pid, 0
一样简单。未能执行此操作会导致已终止或“僵尸”进程累积。有关更多信息,请参阅 perlfunc 中的“waitpid”。
如果您尝试从子进程的 stdout writer 和 stderr writer 中读取,您将遇到阻塞问题,这意味着您将希望使用 select() 或 IO::Select,这意味着您最好使用 sysread() 而不是 readline() 来处理常规内容。
这非常危险,因为您可能会永远阻塞。它假定它将与类似 bc(1) 的内容进行通信,既向其写入又从中读取。这可能是安全的,因为您“知道”诸如 bc(1) 之类的命令将一次读取一行并一次输出一行。但是,诸如 sort(1) 之类的程序首先读取其整个输入流,很可能导致死锁。
此方法的主要问题是,如果您无法控制在子进程中运行的源代码,则无法控制它对管道缓冲区所做的操作。因此,您不能仅仅向 cat -v
打开一个管道并持续从其中读取和写入一行。
与 Open3 类似,但没有 STDERR 捕获。
这是一个 CPAN 模块,它具有比 Open3 更好的错误处理和更多功能。
参数的顺序不同于 open2()。