3 回答

TA貢獻1836條經驗 獲得超4個贊
直到今天我才意識到這個獎項,當時一些菜鳥試圖將UUOC找我的答案之一。那是一個cat file.txt | grep foo | cut ... | cut ...
。我給了他一個想法,然后訪問了他給我的鏈接,他提到了這個獎項的來源和這樣做的做法。進一步的研究使我想到了這個問題。有些遺憾的是,盡管有意識地考慮,但沒有一個答案包括我的理由。
我本不想在回應他時采取防御的態度。畢竟,在我年輕的時候,我會把命令寫成grep foo file.txt | cut ... | cut ...
因為無論你做什么grep
我們學習了文件參數的位置,它已經知道第一個是模式,而后面的是文件名。
這是一個有意識的選擇cat
當我回答這個問題時,部分原因是“品味好”(用LinusTorvalds的話來說),但主要是為了一個令人信服的功能原因。
后一個原因更重要,所以我會先說出來。當我提供管道作為解決方案時,我希望它是可重用的。很可能會在另一條管道的末端添加一條管道,或將其拼接到另一條管道中。在這種情況下,帶有grep文件參數的grep會破壞可重用性,而且很可能會這樣做。靜默如果文件參數存在,則沒有錯誤消息。I.,即grep foo xyz | grep bar xyz | wc
會給你多少行xyz
含bar
當您期望包含兩者的行數時foo
和bar
。在使用之前,必須將參數更改為管道中的命令很容易出錯。再加上沉默失敗的可能性,它就變成了一種特別陰險的做法。
前一個原因也并非不重要,因為“有眼光“僅僅是直覺上的潛意識的理由,像上面的沉默失敗,你無法想到的時候,當某個人需要教育時,說”但那貓不是無用的“。
但是,我也會努力使我提到的前一個“好品味”的原因有意識。這與Unix的正交設計精神有關。grep
不cut
和ls
不grep
。所以至少grep foo file1 file2 file3
違背了設計精神。做這件事的正交方法是cat file1 file2 file3 | grep foo
?,F在,grep foo file1
只是一個特例grep foo file1 file2 file3
如果你不這樣對待它,你至少是在消耗大腦的時鐘周期,試圖避免無用的貓獎。
這就引出了我們的論點grep foo file1 file2 file3
正在連接,而且cat
串連,所以它是適當的cat file1 file2 file3
但因為cat
沒有連接到cat file1 | grep foo
因此我們違背了cat
以及萬能的Unix。如果是這樣的話,那么Unix將需要一個不同的命令來讀取一個文件的輸出并將其吐出到stdout(而不是對其進行分頁,也不只是一個純的stdout)。所以你會遇到你說的那種情況cat file1 file2
或者你說dog file1
認真地記住要避免cat file1
為了避免獲獎,同時也要避免dog file1 file2
因為希望…的設計dog
如果指定多個文件,則會引發錯誤。
希望在這一點上,您同情unix設計器沒有包含一個單獨的命令來向stdout吐出一個文件,同時還命名了cat
而不是給它取別的名字。<edit>
刪除不正確的注釋<
事實上,<
是一種高效的不復制工具,可以將文件吐出到stdout,您可以將其定位在管道的開頭,因此unix設計器確實包含了一些專門用于此的內容。</edit>
下一個問題是,為什么命令只是吐出一個文件或將幾個文件連在一起,而不進行任何進一步的處理,這是很重要的呢?原因之一是避免讓每個在標準輸入上操作的Unix命令知道如何解析至少一個命令行文件參數,并在存在時將其用作輸入。第二個原因是避免用戶必須記?。?A)文件名參數的去處;(B)如上所述,避免沉默的管道錯誤。
這就引出了為什么grep
確實有額外的邏輯。其基本原理是允許用戶流暢地使用頻繁使用的命令和單槍匹馬基礎(而不是管道)。這是一個小妥協的正交性,以顯著提高可用性。并不是所有的命令都是這樣設計的,不經常使用的命令應該完全避免文件參數的額外邏輯(記住,額外的邏輯會導致不必要的脆弱性(bug的可能性)。例外情況是允許文件參數,如grep
。(順便提一下,請注意ls
有一個完全不同的理由不僅接受,而且幾乎需要文件參數)
最后,本可以做得更好的是,如果這樣的特殊命令grep
(但不一定ls
)如果指定文件參數時標準輸入也可用,則生成錯誤。

TA貢獻1820條經驗 獲得超9個贊
不!
首先,在什么地方發生重定向并不重要。因此,如果您喜歡將方向重定向到命令的左邊,那很好:
<?somefile?command
是相同的
command?<?somefile
第二,有n+1進程和子外殼在使用管道時發生。這是最明顯較慢的。在某些情況下n應該是零(例如,當您重定向到shell內置的時候),所以使用cat
您正在添加一個完全不必要的新過程。
一般說來,每當你發現自己在使用管道時,就應該花30秒的時間來看看你是否能消除它。(但可能不值得花費超過30秒的時間。)下面是一些管道和過程經常被不必要地使用的例子:
for?word?in?$(cat?somefile);?…?#?for?word?in?$(<somefile);?…?(or?better?yet,?while?read?<?somefile)grep?something?|? awk?stuff;?#?awk?'/something/?stuff'?(similar?for?sed)echo?something?|?command;?#?command?<<<? something?(although?echo?would?be?necessary?for?pure?POSIX)
添加回答
舉報