[精讚] [會員登入]
1775

[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] 08-陣列 #2 --操作 更多perl陣列的操作,如拆開、黏合、取出、加入等等

[PERL] 23-多執行緒 而多執行緒的程式,可在一次執行程式時間,同時進行多線程的計算,在效率上可獲得即大的提升。

[PERL] 位元運算 Bitwise operation PERL的位元運算整理

[PERL] 可用中文取名的中文名函式和package 原來perl 也可以用中文當函式、類別、方法的名稱啊

PERL 正規表達式會用到的符號 PERL在比對時常常會用到符號整理

Freebsd11上安裝PERL模組 freebsd11+ perl module 在freebsd上安裝module還算簡單

我有話要說

>>

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

訪客留言

[無留言]

隨機好文

沒有非誰做不可的事,也沒有不可被取代的人 沒有非誰做不可的事,也沒有不可被取代的人

SELinux 常用指令和檔案 在Redhat系列中,Centos5以後加入了selinux,他並沒有這麼可怕,不必每次看到Selinux ,就想把他

[CodeIgniter3] 解決無法上傳特定檔案(.sb2)的問題 上傳時出現The filetype you are attempting to upload is not allowed,要怎麼解決?

魔球中小女孩唱的歌 The show 魔球中小女孩唱的歌 The show

[CodeIgniter 3] 資料庫的使用方法整理1/2 --Select的使用 [CodeIgniter 3] 資料庫的使用方法整理:Select的使用