開發 Linux 命令列實用程式(轉)

ba發表於2007-08-11
開發 Linux 命令列實用程式(轉)[@more@]   最佳實踐和考慮周全的編碼造就可靠的命令列工具

   本文將指導您學習如何編寫即使對終端使用者而言也足夠簡單的 Linux 命令列實用程式。本文以概述可靠的命令列最佳實踐開始,並以詳細地研究一個有效的選頁工具結束,為您提供動手編寫自己的實用程式所需要的背景知識。
   本文演示如何編寫與 cat、ls、pr 和 mv 等標準命令類似的 Linux 命令列實用程式。我選擇了一個名為 selpg 的實用程式,這個名稱代表 SELect PaGes。selpg 允許使用者指定從輸入文字抽取的頁的範圍,這些輸入文字可以來自檔案或另一個程式。selpg 是以在 Linux 中建立命令的事實上的約定為模型建立的,這些約定包括:

   獨立工作
   在命令管道中作為元件工作(透過讀取標準輸入或檔名引數,以及寫至標準輸出和標準錯誤)
   接受修改其行為的命令列選項
   不久前我為一位客戶開發了 selpg。隨後我將它公佈在一個 UNIX 郵件列表上,結果有許多成員告訴我他們發現這是一個有用的工具。

   該實用程式從標準輸入或從作為命令列引數給出的檔名讀取文字輸入。它允許使用者指定來自該輸入並隨後將被輸出的頁面範圍。例如,如果輸入含有 100 頁,則使用者可指定只列印第 35 至 65 頁。這種特性有實際價值,因為在印表機上列印選定的頁面避免了浪費紙張。另一個示例是,原始檔案很大而且以前已列印過,但某些頁面由於印表機卡住或其它原因而沒有被正確列印。在這樣的情況下,則可用該工具來只列印需要列印的頁面。

   除了包含 Linux 實用程式現實的示例外,本文還有以下特性:

   它用例項說明了 Linux 軟體開發環境的能力。
   它演示了對一些系統呼叫和 C 庫函式的適當使用,其中包括 fopen、fclose、access、setvbuf、perror、strerror 和 popen。
   它實現了打算用於通用目的的實用程式(而不是一次性程式)所應有的那種徹底的錯誤檢查。
   它對潛在的問題提出警告,如在 C 中程式設計時可能出現的緩衝區溢位,並就如何預防這些問題提供了建議。
   它演示瞭如何進行手工編碼的命令列引數解析。
   它演示瞭如何在管道中以及在輸入、輸出和錯誤流重定向的情況下使用該工具。
   命令列準則
   通用 Linux 實用程式的編寫者應該在程式碼中遵守某些準則。這些準則經過了長期發展,它們有助於確保使用者以更靈活的方式使用實用程式,特別是在與其它命令(內建的或使用者編寫的)以及 shell 的協作方面 — 這種協作是利用 Linux 作為開發環境的能力的手段之一。selpg 實用程式用例項說明了下面列出的所有準則和特性。(注:在接下來的那些示例中,“$”符號代表 shell 提示符,不必輸入它。)

   準則 1. 輸入
   應該允許輸入來自以下兩種方式:

   在命令列上指定的檔名。例如:

   $ command input_file

   在這個例子中,command 應該讀取檔案 input_file。

   標準輸入(stdin),預設情況下為終端(也就是使用者的鍵盤)。例如:

   $ command

   這裡,使用者輸入 Control-D(檔案結束指示符)前輸入的所有內容都成為 command 的輸入。

   但是,使用 shell 運算子“

   $ command < input_file

   這裡,command 會讀它的標準輸入,不過 shell/核心已將其重定向,所以標準輸入來自 input_file。

   使用 shell 運算子“|”(pipe)也可以使標準輸入來自另一個程式的標準輸出,如下所示:


   $ other_command | command

   這裡,other_command 的標準輸出(stdout)被 shell/核心透明地傳遞至 command 的標準輸入。

   準則 2. 輸出
   輸出應該被寫至標準輸出,預設情況下標準輸出同樣也是終端(也就是使用者的螢幕):


   $ command

   在這個例子中,command 的輸出出現在螢幕上。

   同樣,使用 shell 運算子“>”(重定向標準輸出)可以將標準輸出重定向至檔案。


   $ command > output_file

   這裡,command 仍然寫至它的標準輸出,不過 shell/核心將其重定向,所以輸出寫至 output_file。

   或者,還是使用“|”運算子,command 的輸出可以成為另一個程式的標準輸入,如下所示:


   $ command | other_command

   在這個例子中,shell/核心安排 command 的輸出成為 other_command 的輸入。

   準則 3. 錯誤輸出
   錯誤輸出應該被寫至標準錯誤(stderr),預設情況下標準錯誤同樣也是終端(也就是使用者的螢幕):


   $ command

   這裡,執行 command 時出現的任何錯誤訊息都將被寫至螢幕。

   但是使用標準錯誤重定向,也可以將錯誤重定向至檔案。例如:


   $ command 2>error_file

   在這個例子中,command 的正常輸出在螢幕顯示,而任何錯誤訊息都被寫至 error_file。

   可以將標準輸出和標準錯誤都重定向至不同的檔案,如下所示:


   $ command >output_file 2>error_file

   這裡,將標準輸出寫至 output_file,而將所有寫至標準錯誤的內容都寫至 error_file。

   如果已將標準輸出重定向至某一位置,也可以將標準錯誤重定向至同一位置。例如:


   $ command 2>&1

   在這個例子中,符號“2>&1”表示“將標準錯誤傳送至標準輸出被重定向的任何位置”,因此錯誤和正常的訊息都將在螢幕上顯示。當然,這是多餘的,因為下面簡單的呼叫


   $ command

   將做同樣的事。在標準輸出已被重定向至其它源,而您希望在同一命令列上將標準錯誤也寫至同一目的地時,該特性就非常有用。例如:


   $ command >output_file 2>&1

   在這個例子中,已首先將標準輸出重定向至 output_file;因此“2>&1”將使標準錯誤也被重定向至 output_file。

   準則 4. 執行
   程式應該有可能既獨立執行,也可以作為管道的一部分執行,如上面的示例所示。該特性可以重新敘述如下:不管程式的輸入源(檔案、管道或終端)和輸出目的地是什麼,程式都應該以同樣的方式工作。這使得在如何使用它方面有最大的靈活性。

   準則 5. 命令列引數
   如果程式可以根據其輸入或使用者的首選引數有不同的行為,則應將它編寫為接受名為選項的命令列引數,這些引數允許使用者指定什麼行為將用於這個呼叫。

   作為選項的命令列引數由字首“-”(連字元)標識。另一類引數是那些不是選項的引數,也就是說,它們並不真正更改程式的行為,而更象是資料名稱。通常,這類引數代表程式要處理的檔名,但也並非一定如此;引數也可以代表其它東西,如列印目的地或作業標識(有關的示例,請參閱“man cancel”)。

   可能代表檔名或其它任何東西的非選項引數(那些沒有連字元作為字首的)如果出現的話,應該在命令的最後出現。

   通常,如果指定了檔名引數,則程式把它作為輸入。否則程式從標準輸入進行讀取。

   所有選項都應以“-”(連字元)開頭。選項可以附加引數。

   Linux 實用程式語法圖看起來如下:


   $ command mandatory_opts [ optional_opts ] [ other_args ]

   其中:

   command 是命令本身的名稱。

   mandatory_opts 是為使命令正常工作必須出現的選項列表。
   optional_opts 是可指定也可不指定的選項列表,這由使用者來選擇;但是,其中一些引數可能是互斥的,如同 selpg 的“-f”和“-l”選項的情況(詳情見下文)。
   other_args 是命令要處理的其它引數的列表;這可以是任何東西,而不僅僅是檔名。
   在以上定義中,術語“選項列表”是指由空格、跳格或二者的結合所分隔的一系列選項。

   以上在方括號中顯示的語法部分可以省去(在此情況下,必須將括號也省去)。

   各個選項看起來可能與下面相似:


   -f (單個選項)
   -s20 (帶附加引數的選項)
   -e30 (帶附加引數的選項)
   -l66 (帶附加引數的選項)

   有些實用程式對帶引數的選項採取略微不同的格式,其中引數與選項由空格分隔 — 例如,“-s 20” — 但我沒有選擇這麼做,因為它會使編碼複雜化;這樣做的唯一好處是使命令易讀一些。

   以上是 selpg 支援的實際選項。

   selpg 程式邏輯
   如前面所說的那樣,selpg 是從文字輸入選擇頁範圍的實用程式。該輸入可以來自作為最後一個命令列引數指定的檔案,在沒有給出檔名引數時也可以來自標準輸入。

   selpg 首先處理所有的命令列引數。在掃描了所有的選項引數(也就是那些以連字元為字首的引數)後,如果 selpg 發現還有一個引數,則它會接受該引數為輸入檔案的名稱並嘗試開啟它以進行讀取。如果沒有其它引數,則 selpg 假定輸入來自標準輸入。

   引數處理


   “-sNumber”和“-eNumber”強制選項:
   selpg 要求使用者用兩個命令列引數“-sNumber”(例如,“-s10”表示從第 10 頁開始)和“-eNumber”(例如,“-e20”表示在第 20 頁結束)指定要抽取的頁面範圍的起始頁和結束頁。selpg 對所給的頁號進行合理性檢查;

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-947575/,如需轉載,請註明出處,否則將追究法律責任。

相關文章