`tail -f` 部分消耗最后一行,不关心换行符或 nul

`tail -f` 部分消耗最后一行,不关心换行符或 nul

我有一个临时文件(不是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似乎在任何地方都没有任何效果,使用-zfor或用或其他任何方式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

相关内容