我有一个临时文件(不是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
缓冲问题,tail -f
以及使用sync
围绕文件的写入(该文件在上面的函数中是只读的,我不知道如何在尝试读取整个文件之前强制tail
运行sync
线)。stdbuf
似乎在任何地方都没有任何效果,使用-z
for或用或其他任何方式tail
终止字符串也没有效果。$'\0'
唯一阻止它立即发生的事情是循环开始sync
之前的一个while
,但这并不能阻止它在循环开始之后发生。
有没有办法强制tail -f
只读取完整的行?
答案1
短:不直接
长:它不可移植(不在POSIX),但是如果您只对 Linux 感兴趣,您可以通过管道输出通过tail -f
某事是行缓冲。例如,正如建议的那样unix 命令'tail'丢失选项'--line-buffered', GNU grep 有一个--line-buffered
选项,允许你这样做
tail -f "$bg_file" | grep --line-buffered -E '^.*$'
然而作为手动的指出
--line-buffered
使用行缓冲,这可能是一种绩效惩罚。
(自由BSD有相同的选项和评论2004 年 OpenBSD, 不是POSIX然而...)。
文档没有指出这一点,但是2001年首次提交做了心里所花的时间fflush
。