內容

名稱

IPC::Open2 - 使用 open2() 開啟一個同時可讀寫的程序

概要

use IPC::Open2;

my $pid = open2(my $chld_out, my $chld_in,
  'some', 'cmd', 'and', 'args');
# or passing the command through the shell
my $pid = open2(my $chld_out, my $chld_in, 'some cmd and args');

# read from parent STDIN and write to already open handle
open my $outfile, '>', 'outfile.txt' or die "open failed: $!";
my $pid = open2($outfile, '<&STDIN', 'some', 'cmd', 'and', 'args');

# read from already open handle and write to parent STDOUT
open my $infile, '<', 'infile.txt' or die "open failed: $!";
my $pid = open2('>&STDOUT', $infile, 'some', 'cmd', 'and', 'args');

# reap zombie and retrieve exit status
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;

說明

open2() 函數會執行指定的指令,並連接 $chld_out 以供讀取,以及 $chld_in 以供寫入。這是您在嘗試

my $pid = open(my $fh, "|cmd args|");

$chld_in 檔案控制代碼將開啟自動刷新。

如果 $chld_out 是字串(也就是裸字檔案控制代碼,而不是 glob 或參考),且以 >& 開頭,則子代會將輸出直接傳送至該檔案控制代碼。如果 $chld_in 是以 <& 開頭的字串,則 $chld_in 會在父代中關閉,而子代會直接從其中讀取。在兩種情況下,都會建立 dup(2),而不是 pipe(2)

如果讀取器或寫入器是空字串或未定義,這將會被自動產生的檔案控制代碼取代。如果是這樣,您必須在參數槽中傳遞一個有效的左值,以便可以在呼叫方中覆寫它,否則會引發例外。

open2() 會傳回子程序的程序 ID。它不會在失敗時傳回:它只會引發符合 /^open2:/ 的例外。但是,子代中的 exec 失敗不會被偵測到。您必須自行捕捉 SIGPIPE。

open2() 沒有在子程序結束後等待並回收它。除了在讓作業系統處理此問題可以接受的短程式之外,您需要自行執行此操作。這通常只要在您完成程序時呼叫 waitpid $pid, 0 即可。未能執行此操作可能會導致累積廢棄或「僵屍」程序。請參閱 perlfunc 中的「waitpid」 以取得更多資訊。

這整個事件相當危險,因為您可能會永遠封鎖。它假設它會與類似 bc(1) 的東西交談,同時寫入和讀取它。這大概很安全,因為您「知道」像 bc(1) 這樣的指令一次會讀取一行並一次輸出。然而,像 sort(1) 這樣的程式會先讀取其整個輸入串流,很容易造成死結。

此方法最大的問題在於,如果您無法控制在子處理序中執行的原始碼,您就無法控制它如何處理管線緩衝。因此,您無法只開啟一個管線至 cat -v 並持續讀取和寫入一行。

CPAN 中的 IO::PtyExpect 模組可以協助處理這個問題,因為它們提供了一個真正的 tty(實際上是一個偽 tty),它會讓您回到呼叫的指令中進行行緩衝。

警告

引數順序與 open3() 不同。

另請參閱

請參閱 IPC::Open3,以取得同時處理 STDERR 的替代方案。此函數實際上只是 open3() 的包裝函數。