bash - 为什么当我使用 `>` 操作符对已重定向的文件进行 `tail -f` 时出现不一致的行为
问题描述
我正在编写一些脚本,并遇到了这种行为。这是一个简化的例子。
在一个 tty 上,
# touch file
# tail -f file 2> /dev/null
在另一个 tty 上,在同一目录中,运行以下脚本:
#!/bin/bash
for i in {1..15}; do
echo $i > ./file
sleep 2
done
为什么tail -f
在我使用操作符时命令没有正确反映文件更改>
?如果我使用>>
附加运算符,它会按预期工作。
最终,已使用>
操作员重定向的文件的尾部显示如下:
1
2
6
7
9
15
解决方案
tail -f
仅可靠地检测附加的更改。它尝试检测文件被截断、缩短或以其他方式未在末尾修改的写入,但这种检测是参差不齐的。它可以检测到其中的一些,但会漏掉很多。
算法
- tail 使用inotify来观察变化。
- 当发生更改事件时,它会快速运行fstat()来检查文件的元数据,包括其大小。
- 如果大小较大,则假定已附加数据并读取添加的数据。
- 如果大小更小,它会打印“文件被截断”并从头开始。
结果
>
将文件截断为 0,然后写入新内容。tail 是否检测到这些类型的写入是命中还是未命中。如果您写入更大或相等数量的字节,它通常会错过这些写入。
第 4 步确保它能够可靠地检测文件长度是否缩短。如果您修改循环以在每次迭代中连续编写较短的字符串,则 tail 将检测每一个:
for i in {1..5}; do for ((j=6-i; j>=0; --j)); do echo $i; done > file sleep 2 done
tail: file: file truncated 1 1 1 1 1 tail: file: file truncated 2 2 2 2 tail: file: file truncated 3 3 3 tail: file: file truncated 4 4 tail: file: file truncated 5
第 1 步和第 2 步之间存在竞争条件。当您运行时
echo $i > file
,有两个背靠背修改:文件被截断,然后$i
被写入。如果 tail 能够fstat()
在两个修改之间运行,那么它会检测到截断。但是,如果它太慢,它就会错过它。这就是通常发生的情况,这就是为什么它错过了大部分但不是全部的写入。这也解释了为什么睡觉没有帮助。要消除竞争条件,您需要在 truncating 和 writing 之间睡觉
$i
,而不是在之后。事实上,你可以这样做:
for i in {1..15}; do (sleep 2; echo $i) > file; done
> file
立即运行并截断文件。然后脚本在写入前休眠两秒钟$i
。两种修改之间有明显的差距。正如预期的那样,tail 现在检测到每一次写入:
1 tail: file: file truncated 2 tail: file: file truncated 3 tail: file: file truncated 4 tail: file: file truncated 5 tail: file: file truncated 6 tail: file: file truncated 7 tail: file: file truncated 8 tail: file: file truncated 9 tail: file: file truncated 10 tail: file: file truncated 11 tail: file: file truncated 12 tail: file: file truncated 13 tail: file: file truncated 14 tail: file: file truncated 15
推荐阅读
- python - 为什么 -7 在这个函数中返回 True?
- gitlab - 如何呈现嵌入的降价代码段?
- python - 给定年份的公司赫芬达尔指数
- mysql - 如何使用递归公用表表达式删除结果?
- navigation - 按下按钮时触发 LinkClicked
- asp.net-mvc - 我们是否基于应用程序域创建 google oauth 应用程序,以不将每个子域注册为授权的 JavaScript 来源并重定向 uri?
- vue.js - 通过传入布尔属性在输入和更改事件之间切换
- windows - 日志文件自动更改 - PostgreSQL
- android - 闪屏活动在过渡时可以有圆角吗?
- firebase - 使用 JavaScript 向 Web 获取通知(消息)