網路農夫 --  Home 網路農夫 --  Home
網路農夫 --  Home
wait.....

3-4 管線(pipeline)觀念與運用

將一個指令的標準輸出重導向,做為下一個指令的標準輸入,像這種連結兩個指令間標準輸出、輸入的特殊功能,便稱為管線(pipeline)。在 C shell 中定義了兩個關於管線功能的特殊符號。如下:

“|” 只導向標準輸出(stdout)

“|&” 導向標準輸出與標準錯誤(stdout and stderr)

先讓我們來看看一個例子:

2 % who
akira ttyp0 Sep 9 17:49 (akirahost)
akk ttyp1 Sep 9 17:49 (akirahost)
simon ttyp2 Sep 9 17:49 (akirahost)
3 % who > file.a ; wc -l < file.a ; \rm -f file.a
3
4 % who | wc -l
3

從上面的例子中,要計算 who 指令的輸出有幾行,以輸出重導向的做法是,先將 who 指令輸出重導向到一個檔案“file.a”中,再將該檔案重導向到指令 wc -l 來計算行數。最後再將產生的資料檔案“file.a”清除。這過程中有三個硬磁的 I/O 動作。但如果使用管線的方法如行 4 所示,它根本沒有硬磁的 I/O 動作,是不是比行 3 所下的指令方便多了呢。而且不需產生任何檔案,省略的 I/O 動作,對使用效率來說是比較好的使用方式。

我們再來看看下面這個例子:

% find ~ -name "*.dat" -print | rm

上面的指令是用指令 find 找尋 home 目錄下檔名為“*.dat”並將它列出,再將列出的訊息運用管線通入指令 rm 去將這些檔案清除。說起來好像是一點問題也沒有,其實是一點用也沒有。要不然馬上上機試一試。這個指令的錯不在於指令 find 或運用了管線,而是在於指令 rm 身上,因為它的引數不接受標準輸入。所以你無法這樣使用。不過指令 find 本身的語法有支援像上面的運用,如下示:

% find ~ -name "*.dat" -exec rm -i "{}" \;

當指令 find 在找到一個相符的檔名時會執行指令 rm -i,讓你鍵入 y 或 n 來決定是否要清除該檔案,之後,指令 find 會再繼續尋找相符的檔名來做同樣的動作。這樣的功能便與上面那個使用管線不成的指令作用相同了。

所以在管線的運用時一定得注意前後指令的關係,及是否指令接受標準輸入等問題。你越用心去嘗試將可得到越方便的越佳的使用效率。看下面這個運用:

% ps axu | egrep 'cron|nfsd|pcnfsd' | egrep -v egrep | lpr

從一個系統訊息經過數個管線的連接,將這個系統訊息篩選處理成我們所要的資訊,並直接將它由列表機印出。或者是像下面的運用:

% cat files | grep pattern | sort -u | more

像這類的運用都是相當得宜的作法。

 

3-4-1 相關的輔助指令 - tee 指令的功能

 

對管線的功能而言,並無法像輸出重導向可產生檔案。這是管線功能的不足與限制之處。但不要緊, UNIX 有一指令可填補這項缺撼,這便是 tee 指令。當行 4 指令修改為“who | tee file.a | wc -l”,則指令 who 的輸出一方面由 tee 指令儲存到檔案“file.a”中,一方面又 pipe 到指令 wc -l 去計算 who 輸出的行數。這個指令你可用在備份檔案的指令,特別是當你想一面在螢幕上查看檔案備份的情況,而又希望將備份檔案的訊息儲存成檔案時。如下例:

1 % tar cvf /dev/rst8 /user1 /user2 |& tee backup.data

另外該指令也提供了一個 -a 的選項,來讓你能將訊息加到指定檔案的內容之後。請看以下的運用。

2 % date | tee -a log.log
Sun Nov 26 22:15:15 CST 1995

在指令 2 中,我們再一次使用 tee 指令將指令 date 的輸出加到檔案“backup.data”中,但因為指令 tee 有加上選項 -a,所以並不會將原檔案的內容清除掉。怎麼樣是不是很好用呢?

 

版本:Beta-2001-05 -- 網路農夫