2011年3月19日 星期六

習作-使用Open2來與外部程式交談

# demo 使用Open來與外部程式交談
# unix指令wc : print newline, word, and byte counts for each file
# 在perl程式內執行wc, 提供計算資料以及取回計算結果

use strict;

use IPC::Open2;
use IO::Handle;

# init file handle
my $read_fh  = IO::Handle->new();
my $write_fh = IO::Handle->new();

# 使用open2建立可與之交談的子程序
my $childpid = open2($read_fh, $write_fh, 'wc');

# 提供資料
$write_fh->print("abc def\n24 187\n");
# 關閉(結束)input handle, 否則wc會一直等待
$write_fh->close();

# 取回結果(可能多行, 使用陣列)
my @wc = <$read_fh>;

# 關閉(結束)input handle, 否則wc會一直等待
$read_fh->close();

print "$_\n" for (@wc);
# 印出 2 4 15

# 等待確認子程序已結束
waitpid($childpid, 0);

exit 0;

在Perl程式裡面執行外部程式的方法很多,如何選擇使用,主要還是取決於需求以及外部程式的特性。

有一類如系統指令,並不提供API,通常的用法就是在shell環境下,以指令的方式或者shell script的方式使用,用眼睛閱讀解讀,執行的輸出結果,或者再把它的輸出經由pipe,當成另外一個指令的輸入或者儲存寫到檔案裡面。


如果需要能夠動態決定輸入內容,以及靈活使用(比如判斷、轉換、組成、轉送...)它的輸出,Perl提供open2這個基本函式,經由線上文件可以瞭解它的使用方法,以及需要注意(比如I/O buffer的觀念)的地方。

外部程式並非永遠正確執行(比如可能找不到,或者傳入的內容不符合他的預期...),這點就需要檢查$?變數內容。

為什麼是open2(),因為它只處理了STDOUT & STDIN這兩個File Handle,如果還需要STDERR的內容,那就要使用open3(),照文件說明所說,open2()其實是open3的wrapper,也就是它最終是去呼叫open3(),使用這個函式需要注意的是File Handle的Input/Output方向。

然而,現在寫程式,比較不建議直接使用open2這些基本的函式呼叫了,因為你需要處理一些不必要的細節,學會使用CPAN上的模組,比如IO::CaptureOutput或者IPC::Cmd
可以簡化一些處理細節,程式的bug也會減少很多。

沒有留言:

張貼留言