[精讚] [會員登入]
1727

[PERL] 24-呼叫系統程式及評估

Perl 如何呼叫系統程式並取回結果?

分享此文連結 //n.sfs.tw/15489

分享連結 [PERL] 24-呼叫系統程式及評估@新精讚
(文章歡迎轉載,務必尊重版權註明連結來源)
2021-11-09 18:07:00 最後編修
2021-11-08 00:19:27 By 張○○
 

自動目錄

程式上偶爾會需要取用到系統或其它非PERL本身的程式,PERL該如何呼叫?

PERL提供 system, exec, 反單引號` 等函數可供叫用,以下分別來說明。

呼叫外部程式

使用system來執行外部程式

假如在perl中想要呼叫其它的程式,稱之為「外部程式」,可以直接使用 system這個函數,例如 pwd顯示目錄的目錄及ls傾印:

system("pwd");
system("ls");

輸出結果就和我們平時下指令沒什麼差別。

要注意的是,每一個system指令都是獨立的,並不是在同一個狀態(session)之下,舉個例子來說,我們希望傾印此目錄所在位置的上一層目錄,如果寫成這樣:

system("cd ../");
system("ls");

看起來有先切換到上一層目錄再執行傾印檔案,結果卻還是印出目前的目錄下的檔案,並不會印出上一層的檔案,這顯然不是我們想像的結果。

當然,解決的方法並不難,例如可以把指定寫在同一行,並用分號來分隔;或是指定目錄來傾印:

system("cd ../; ls");
system("ls ../");

如果指令中帶有引數,也可以使用陣列的方法傳入:

@args = ("command", "arg1", "arg2");
system(@args) == 0 or die "system @args failed: $?"

以上 $? 是標準錯誤(STDERR)回傳的結果。

system的執行方式是執行後並等待回應,換句話說,假設叫用的外部程式有狀況,程式也只能等待,

正常的情況下,當叫用的外部程式結束後,會回到perl的行程並往下執行。

 

使用exec來執行外部程式

exec 和system 類似,只是exec不會回傳結果。

但是和system一樣,假如呼叫的指令本身就具有傾印結果的作用,則不在此限,例如執行以下的指令:

exec("ls");
exec("date");
exec("echo 'SOME TEXT'");

簡單來說,system執行時,原本的 Perl 程式會待在哪裡沒事做等待 system 裡執行的指令結束。但是exec 執行時,

原本Perl程式後面的行程就已經不存在了,只剩下執行 exec中命令的行程,而且該行程執行完畢之後,也不再返回原本的 Perl 行程。

例如下面的程式:

exec("date");
print "After exec\n";

執行結果

2021年11月 9日 週二 11時26分47秒 CST <== 原本系統指令date的回應
<<'After exec'這行不會被印出來,同時perl已經結束。>>

 

使用單引號來執行外部程式(backticks)

 

單引號的行為就像是直接shell的叫用方法

`外部程式`

上面的引號是反單引號 ` ,鍵盤上數字1左邊那個按鍵,英文叫作backticks,千萬不要用錯。

反單引號是將送到標準輸出(STDOUT)的結果當回傳值,換句話說,原本要送到標準輸出的結果就會被劫斷,例如本來要印出日期時間的指令date:

`date`;  <== 沒有任何反應,輸出被 `` 本身劫掉。
print `date`; <== 印出日期時間

反單引號也可以使用 qx() 來代替,例如以下兩種是等義:

`date`;
qx(date);

 

取回叫用程式的執行結果

實務上叫用系統程式,有時需要取回執行的結果,我們先寫程式觀察上面的這三種方法再作結論:

$a=`date`;
print "單引號:$a\n";

$b= system("date");
print "system函數:$b\n";

$c= exec("date");
print "exec函數:$c\n";

執行結果

單引號:2021年11月 9日 週二 11時49分44秒 CST

2021年11月 9日 週二 11時49分44秒 CST
system函數:0
2021年11月 9日 週二 11時49分44秒 CST

第8行 因為exec後面的部分不會被執行,所以第8行不會顯示

由此可以看到只有反單引號可以正確的將傾印的結果傳給變數$a,system回傳一個0(此例回傳空值),而exec執行完即結束。

因此使用反單引號正是我們需要的。

 

評估 eval 的使用

PERL 提供了一個評估(eval)的方法,從字面上很難理解他的意義,簡單來說,eval就像是一個沙盒(sandbox)或是perl的虛擬機,我們可以在沙盒中執行某個函數或是程式區塊。

假設在這裡出了錯,PERL並不會因為錯誤而中止。

舉例來說,以下是一個一定會出錯的式子,因為除以0不被計算機接受。

print 1/0;

執行結果

Illegal division by zero at 01.pl line X

 

就算出錯,如果我們也希望程式不要因此報錯或是不要中止的話,可以使用評估的方法,把原本的指令放在雙引號中,再交給eval執行。:

eval print 1/0;

執行結果

<<沒有任何輸出也不會報錯>>

 

但是如此,會不知道在eval裡面到底發生了什麼事,還好有錯誤的話,eval會把錯誤寫到變數 $@ 中,只要判斷 $@是否為空字串即可。

eval print 1/0;
print $@;

執行結果

Illegal division by zero at (eval 1) line 1.

一般而言,只要判斷 $@是否為空字串,否則就印出警告,只要評估中沒有錯誤, $@ 一定是空字串。

eval print 1/0;
warn $@ if $@;

 

評估可以不只寫成一行,也可以用大括號來包圍一個區塊,最後的分號很常被漏掉

eval { ...程式碼 ... };

例如下面的範例,在eval 中的變數能夠被eval外面讀到

eval {
 $a=123;
 $b=0;
 print $a/$b;
};
print $a;

執行結果

123

上面的範例可以發現第4行錯誤的計算並沒有顯示,但也沒有報錯,這就是評估好用的地方,類似在其它程式語言中的 try...catch 語法。

eval 還有其它作用,留待有興趣的人自行研究。

結論

1. 呼叫外部程式可用 system、exec、backticks 等內建的方式。

2. 呼叫外部程式並等待使用 system,呼叫外部程式後原perl程序就不執行用exec,需要取得執行結果用 backticks。

3. eval可以讓指定放在沙盒中執行,不因錯誤而停止。

 

參考資料

[1] https://stackoverflow.com/questions/799968/whats-the-difference-between-perls-backticks-system-and-exec

[2] http://puremonkey2010.blogspot.com/2010/09/perl-ch16.html

 

 

上一篇 23-多執行緒
回到目錄 01-撰寫第一隻PERL程式/目錄
下一篇 25-通訊和網路

 

 

END

你可能感興趣的文章

[PERL] 22-日期和時間 Perl 取得日期時間的方法整理,使用 localtime等多種函數

關於Perl,你得知道這幾點 Perl 有不少奇異的地方,值得看一看

[PERL] 中文字字串拆解,把中文字串逐字拆開 中文字字串拆解是門學問

[PERL] 16-字串取代和置換 Perl 字串比對及置換

[PERL] split 寫法 Perl 將字串分開可以用 split 這個函數,此函數可以用Regex作分隔判斷

[PERL] Perl 不立即輸出的列印緩衝區問題 解決Perl 不立即輸出而是最後一次輸出的列印緩衝區問題

我有話要說

>>

限制:留言最高字數1000字。 限制:未登入訪客,每則留言間隔需超過10分鐘,每日最多5則留言。

訪客留言

[無留言]

隨機好文

使用Google尋找你的手機 這近發現google竟然可以用來找android的手機,而且不需要經過什麼設定或安裝軟體。

詭異的創業思維 創業的思維中,有多少銀彈,有多少技術,有多少人脈,有多少時間等等,每個都要考慮進去,以熱忱建立的關係脆弱的像蘇打餅乾一樣..

維修海棉拖把頭 這類型的海棉拖把很好用,可是這近發現海棉頭越來越不耐用,也許是錯覺,以往都能用個三四個月,現在二個月就差不多掉下來。 這

Sound of Music @比利時中央車站 比利時中央車站的快閃表演:「真善美」

真正的喜悅 幾種喜悅的類型,雖然很簡單,卻是很多人百思不得其解的難題..