Fifo

從 Ubuntu 中的命名管道一次讀取 n 行

  • February 27, 2021

我正在 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. 一次讀取一個字節,直到找到第二個換行符。
  2. 查看(不消耗)管道的內容以查看第二個換行符的位置,然後一次性讀取盡可能多的數據。
  3. 讀取塊中的輸入,但如果他們發現他們已經閱讀了超過兩行的內容,則將他們閱讀過多的內容放回管道上。

1 在許多系統上很昂貴,因為這是read()每字節一個系統呼叫。2 和 3 不適用於所有系統,因為並非所有系統都支持窺視管道或將數據放回管道,而且當多個程序同時從管道讀取時,這也不可靠。

所以一般來說,除了少數例外,命令通常不會費心閱讀當他們的輸入不可搜尋時他們被告知的確切行數。

在大多數實現中headhead -n2將輸出其輸入的前兩行,但可能會消耗更多輸入。一個值得注意的例外是headksh93 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

引用自:https://unix.stackexchange.com/questions/548196