
透過管道連結 bash 命令時是否發生了任何象徵性的事情,或者都是計算-傳遞-計算-傳遞?
例如,在 中head t.txt -n 5 | tail -n 2
,正在head t.txt -n 5
計算然後tail -n 2
執行它。或者首先有一些抽象告訴 shell 要讀取第 3 行到第 5 行?在這個例子中可能沒有什麼區別,但我想在其他情況下可以。
答案1
shell 使用pipe(2)
系統呼叫在核心中建立一個有界緩衝區,該緩衝區具有兩個檔案描述符,一個使進程能夠寫入緩衝區,另一個使進程能夠從緩衝區讀取。
考慮一個簡單的情況:
$ p1 | p2
在這種情況下,從概念上講,shell 創建上述管道fork()
s ,子級將其標準輸出流連接到管道的寫入端,然後是子級exec()
s p1
。接下來,shellfork()
再次 s ,子級將其標準輸入流連接到管道的讀取端,然後是子級exec()
s p2
。 (我說從概念上來說因為 shell 可能會以不同的順序執行操作,但想法是相同的。
那時,p1
和p2
正在同時運行。 p1
將寫入管道,核心會將寫入的資料複製到緩衝區。 p2
將從管道中讀取,核心將從緩衝區複製讀取的資料。如果管道已滿,則核心將阻塞p1
其調用,write()
直到p2
從管道中讀取某些內容,從而釋放一些空間。如果管道為空,則核心將阻塞p2
其調用,read()
直到將p1
更多資料寫入管道。
答案2
您建議的兩種型號中。計算傳遞-計算傳遞是最接近的。 shell 只是連線進程。它對他們在做什麼一無所知。
除了, 執行順序未定義。它們實際上同時運行。然而,左邊的必須先輸出字節,然後右邊的才輸入位元組。數據從左到右流動。資料從第一個命令流出,從其標準輸出流出,然後流入下一個進程的標準輸入,在那裡進行處理,然後從標準輸出流出,可以透過管道傳輸到另一個進程,等等等等等等
如果沒有重定向>
、<
等等或從檔案中讀取。然後看起來像這樣。
┌───────────┐ ┌───────────┐ ┌─────────────┐
Terminal⇨│Process one│⇨│Process two│⇨│Process Three│⇨Terminal
└───────────┘ └───────────┘ └─────────────┘