2012-04-01 64 views
5

我想知道這裏的最佳做法。假設我想獲取文件某行的內容。我可以使用單行shell命令來獲得我的答案,或者編寫一個子例程,如下面的代碼所示。在Perl腳本中,我們應該使用shell命令還是調用模仿shell操作的Perl函數?

的文本文件命名爲some_text

She laughed. Then both continued eating in silence, like strangers, 
but after dinner they walked side by side; and there sprang up 
between them the light jesting conversation of people who are free 
and satisfied, to whom it does not matter where they go or what 
they talk about. 

代碼來獲取文件

#!perl 
use warnings; 
use strict; 

my $file = "some_text"; 
my $lnum = 5; 
my $shellcmd = "awk 'NR==$lnum' $file"; 
print qx($shellcmd); 
print getSrcLine($file, $lnum); 

sub getSrcLine { 
    my($file, $lnum) = @_; 
    open FILE, $file or die "$!"; 
    my @ray = <FILE>; 
    return $ray[$lnum-1]; 
} 

我問這個的第5行的內容,因爲我看到了很多的Perl腳本,其中在某些時候,一個shell命令被調用,而在稍後的某個時間點,通過調用(庫或手寫)函數完成相同的任務,例如rm -rfFile::Path::rmtree。我只是想讓它一致。

建議做什麼?

+0

Recomended方式取決於代碼的意圖。如果你想在Non Unix機器上執行,然後去perl庫,否則看看我已發佈的鏈接..希望這有助於.. – Rajeev 2012-04-01 18:44:52

+0

也許每個腳本是在一段時間內開發的,可能是由多個程序員開發的。腳本發展了,代碼不是100%自我一致的,部分取決於那些涉及Perl或shell的經驗有多少。 – 2012-04-01 18:51:56

+2

請注意,雖然汲取整個5行文件以獲得第五行不是太痛苦,但它可能是獲得第五行百萬行文件的次優策略。 – 2012-04-01 18:54:31

回答

13

如果操作有Perl函數,Perl認爲您應該使用它的版本。但是,您舉了一個Perl 模塊的示例,它提供了一種純Perl方式來執行此操作。這是非常不同的。有沒有一個簡單的答案(因爲在大多數的事情),所以你必須自己決定做什麼:

  • 是否純Perl的方法做正確的呢?例如,File::Copy有一些限制,因爲它會爲用戶做出一些尷尬的決定,所以很多人都認爲它已經壞了。例如,參見File::Copy versus cp/mv

  • 純Perl方法在可接受的時間內完成嗎?有時外部程序的速度要快幾個數量級。有時會慢很多。外部命令通常在一系列系統(例如所有類似linux的系統)中是可移植的,但可能並不跨系列(例如Windows和Linux)。你的容忍可能會影響你的答案。即使您認爲自己運行的是相同的命令,不同類型的unix系統也可能具有不同的操作開關。

  • 將複雜的參數(空格,引號和特殊字符)傳遞給外部命令會讓你哭泣。你必須做很多繁瑣的工作才能確保你正確處理參數。但Perl子程序並不在乎。

  • 當你使用外部命令時,你必須更多地關注你在做什麼。如果您只打電話rm,Perl將搜索您的PATH,並使用第一個稱爲rm的東西。這並不意味着它就是你認爲的程序。我在掌握Perl的「安全編程技巧」中寫了相當多的內容。

  • 如果純Perl的方法需要一個模塊,特別是如果該模塊有很多複雜的依賴關係,你可能會爲依賴或分發地獄的道路是英寸

就我個人而言,我從純粹的Perl方法開始,直到它不適用於這種情況。

對於您的特定示例,我會使用Perl。對awk來說,這是一個原始的Perl,簡直太奇怪了。你應該能夠做到awk所做的一切正確的Perl。如果你有一個awk程序,您可以用A2P程序將其轉換成Perl:

NR==5 

A2P輪流到這一點(模在開始進行一些設置位):

while (<>) { 
    print $_ if $. == 5; 
} 

注意即使你有第五行,它仍然會掃描整個文件。但是,您可以使用翻譯的程序作爲開始:

while (<>) { 
    if($. == 5) { 
     print; 
     last; 
     } 
} 

我不認爲您應該掏出一些其他程序來避免該Perl代碼。

要刪除一個目錄樹,我喜歡File::Path。它有一些依賴關係,但它們都在Perl標準庫中。如果有的話,與該模塊相關的痛苦幾乎沒有。我會使用它,直到遇到無法正常工作的問題。

+0

謝謝你的詳細解答。我特別喜歡關於安全性的觀點,因爲在Perl中編寫代碼時我並不認爲它很多。另外,我遇​​到了a2p程序,這非常方便!我現在確信,只要Perl能夠可靠地做同樣的事情,我就應該儘量避免在腳本中使用外部shell命令。 – Unos 2012-04-02 01:49:20

+0

優秀的答案。唯一的補充是關於腳本的要求。如果您正在編寫一次性使用程序,那麼爲了節省您的時間,對* nix命令進行脫殼是非常合理的。我最近在Datbase導出到導入腳本的數據轉換腳本中執行了此操作。對於部分外部命令來說,它更快,並且腳本在正確運行一次後就會被拋棄。如果我正在編寫一個每週都會執行類似功能的程序,我會花時間在Perl中正確實現它,如果可以的話。 – 2012-04-02 17:43:35

4

如果您希望您的應用程序可以移植到非unix系統,那麼絕對使用Perl編寫代碼。

如果不是,那真的取決於你......創建一個新的過程比較慢,但是如果它對於任務不重要,那麼它並不重要。我個人會選擇我可以更快實施的解決方案。

2

在我看來,該代碼的作品應該是第一位的。例如,如果文件名中有空格,則失敗。

使用shell讓因爲你的程序需要適當地產生由sh運行另一個程序更難正確編碼。 (這個問題消失,如果你使用的系統的多ARG版本,以避免外殼。)

此外,使用外部工具可以使它很難處理錯誤。你甚至沒有試圖這樣做!

在另一面,也有使用外部工具多種原因。例如,Perl不提供與cp一樣好的文件複製實用程序;使用sort工具允許您使用有限的RAM對任意大文件進行排序;等