從 Ubuntu 中的命名管道一次讀取 n 行
我正在 Ubuntu 中試驗命名管道,但之前沒有使用它們的經驗。我做了以下事情:
mkfifo pipe ls>pipe& cat pipe
這會將我文件夾中所有文件的列表輸入
pipe
並顯示它們。我正在嘗試一次讀取 2 行管道。所以,我想要一個命令,當執行一次時,會給出文件夾中第一個和第二個文件的名稱。如果再次執行該命令,我想要第三個和第四個文件名。有什麼辦法嗎?我試過了
head -2 pipe
。它顯示了前兩個文件名。但是當它再次被執行時,它就掛了。正確的前進方向是什麼?
您希望在閱讀端保持先進先出。一種方法是讓 bash 為其保留一個打開的文件描述符。
#!/bin/bash mkfifo pipe ls > pipe & exec 8< pipe r2(){ read -ru 8 fn1 read -ru 8 fn2 echo "$fn1" "$fn2" } r2 # print out first 2 files sleep 1 # do something r2 # print out next 2 files.
您需要一個讀取兩行且不超過兩行的命令。
當輸入是不可搜尋的管道時,為了能夠做到這一點*,*命令有三個選擇:
- 一次讀取一個字節,直到找到第二個換行符。
- 查看(不消耗)管道的內容以查看第二個換行符的位置,然後一次性讀取盡可能多的數據。
- 讀取塊中的輸入,但如果他們發現他們已經閱讀了超過兩行的內容,則將他們閱讀過多的內容放回管道上。
1 在許多系統上很昂貴,因為這是
read()
每字節一個系統呼叫。2 和 3 不適用於所有系統,因為並非所有系統都支持窺視管道或將數據放回管道,而且當多個程序同時從管道讀取時,這也不可靠。所以一般來說,除了少數例外,命令通常不會費心閱讀當他們的輸入不可搜尋時他們被告知的確切行數。
在大多數實現中
head
,head -n2
將輸出其輸入的前兩行,但可能會消耗更多輸入。一個值得注意的例外是head
ksh93 shell 的內置函式,如果可以,它會偷看,否則一次讀取一個字節。有些命令可以被告知以確保他們不會讀到他們被告知要處理的最後一行。
使用 GNU
sed
,可以-u
選擇:sed -u 2q
將讀取 2 行(一次 1 個字節),僅此而已。
該
line
實用程序(不再是標準實用程序,因此如今並不總是如此)是一種僅讀取一行的實用程序。
read
內建的要求sh
不超過一行。因此,line
上面的命令可以通過以下方式實現:IFS= read -r line; printf '%s\n' "$line"
(需要注意的是,即使輸入行沒有終止,它也會添加換行符)。
(POSIX 實際上證明刪除是合理
line
的,因為它可以通過 來實現read
)。對於
line
不添加額外換行符並在 eof 上返回 false 的實現。line() { if IFS= read -r line; then printf '%s\n' "$line" else printf %s "$line" false fi }
而且
twolines
只是:twolines() { line && line; }
然後你可以這樣做:
mkfifo pipe ls > pipe & while echo next two lines: twolines do continue done < pipe