Linux

tail -f 部分消耗最後一行,不關心換行符或 nul

  • March 23, 2017

我有一個需要由多個閱讀器腳本監視的臨時文件(**不是fifo/管道)。**每個腳本都使用後台程序來監視臨時文件,使用以下程式碼:

function file_relay {
   # $1 is a regular file to read from
   local bg_file
   bg_file="$1"

   # $2 is a fifo to relay to
   local outfile
   outfile="$2"

   tail -f "$bg_file" | while read -r line
   do
       [[ ! -z "$line" ]] && { printf "%s" "$line" >>"$outfile"; }
   done
}

他們需要在啟動時讀取整個文件,然後注意是否有新行,上面的函式就是這樣做的:

file_relay /tmp/examplefile /tmp/examplefifo &

每個腳本也會向該文件輸出行。所以這是一個多作者和多讀者的情況。

問題是有時tail -f不會等待整行可用,即使我正在使用printf重定向到文件並且字元串末尾有換行符。這會導致讀取的行被損壞,最後一行的第一個單詞被附加在前一行的末尾,所以我得到:

This is one lineThis

代替

This is one line
This is another line

我試圖解決printf’s buffering 、tail -f’ s buffering 以及 use syncaround writes to the file(文件在上面的函式中是只讀的,我不知道如何在嘗試讀取整個文件之前強制tail執行sync線)。stdbuf似乎在任何地方都沒有任何效果,使用-zfortail或終止字元串$'\0'或其他任何東西也沒有。唯一能阻止它立即發生的是循環開始sync之前的單while次,但這並不能阻止它在那之後發生。

有沒有辦法強制tail -f只讀取完整的行?

短:不直接

long:它不是可移植的(不在POSIX中),但是如果您將興趣限制在 Linux 上,您可以通過線緩衝的方式*輸出。例如,正如unix command ’tail’ lost option ‘–line-buffered’*中所建議的,GNU grep 有一個選項,允許您執行此操作tail -f``--line-buffered

tail -f "$bg_file" | grep --line-buffered -E '^.*$'

然而,正如手冊指出的那樣

--line-buffered

使用行緩衝,它可能是一種性能懲罰

FreeBSD在 2004 年與 OpenBSD 有相同的選項和評論,還沒有POSIX …)。

文件沒有指出這一點,但2001 年的初始送出考慮到了花費在fflush.

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