本文將指導您學習如何編寫即使對最終用戶而言也足夠簡單的 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 命令行准則
通用 Linux 實用程序的編寫者應該在代碼中遵守某些准則。這些准則經過了長期發展,它們有助於確保用戶以更靈活的方式使用實用程序,特別是在與其它命令(內置的或用戶編寫的)以及 shell 的協作方面 ― 這種協作是利用 Linux 作為開發環境的能力的手段之一。selpg 實用程序用實例說明了下面列出的所有准則和特性。(注:在接下來的那些示例中,“$”符號代表 shell 提示符,不必輸入它。)
Linux 命令行准則 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 的標准輸入。
Linux 命令行准則 2. 輸出
輸出應該被寫至標准輸出,缺省情況下標准輸出同樣也是終端(也就是用戶的屏幕):
$ command
在這個例子中,command 的輸出出現在屏幕上。
同樣,使用 shell 操作符“>”(重定向標准輸出)可以將標准輸出重定向至文件。
$ command > output_file
這裡,command 仍然寫至它的標准輸出,不過 shell/內核將其重定向,所以輸出寫至 output_file。
或者,還是使用“|”操作符,command 的輸出可以成為另一個程序的標准輸入,如下所示:
$ command | other_command
在這個例子中,shell/內核安排 command 的輸出成為 other_command 的輸入。