“tail -f”,但是在一个被一次又一次重写(下载)的文件上,而不一次又一次地输出内容?

“tail -f”,但是在一个被一次又一次重写(下载)的文件上,而不一次又一次地输出内容?

我有通过 cron 作业下载的日志文件。如果在远程位置更新文件,即使仅附加了数据,本地副本也会从头开始重写。

tail -f像或这样的工具since似乎将此视为“文件已被替换”并再次从头开始输出它们。即重复所有已知的内容。特别是这两个工具在 STDERR 上明确提到了这一点。

因此,如果我在一个终端中调用它:

for j in $(seq 2 4) ; do for i in $(seq 1 $j) ; do echo $i ; sleep 1; done > /tmp/foo; done

tail -f /tmp/foo我在两个终端和tail -F /tmp/foo另一个终端中都收到这些警告:

1
2
tail: /tmp/foo: file truncated
1
2
3
tail: /tmp/foo: file truncated
1
2
3
4

使用 时while sleep 0.25; do since /tmp/foo; done,我收到以下错误消息之一:

1
2
since: considering /tmp/foo to be truncated, displaying from start
1
2
3
since: considering /tmp/foo to be truncated, displaying from start
1
2
3
4

since显式使用 inode 而不是文件名作为文件的键。tail可能会做类似的事情来识别被截断的文件。

我尝试过的另一个“工具”是 Perl 库文件::尾巴,但它有相同的“问题”,只是没有警告(至少在默认设置下)。

所以我想知道:是否有一种方法或工具不查看索引节点,而只查看文件的内容,并且仅在数据尚未附加时才重新启动?

我想要的只是这个输出:

1
2
3
4

(我见过tail -f,但是当文件被删除并重新创建时(不附加),但它没有帮助,因为它仍然从头开始重新输出文件的内容。)

是的,我知道这样的工具要么需要所有看到的(但未截断的)数据的缓存,要么至少需要它的哈希和。

答案1

tail对你的用例来说太聪明了。在这里,你可以这样做:

{
  tail
  while cat; do
    sleep 1
  done
} < /tmp/foo

与 的原始实现相同tail-f1980 年添加到 SysIII 中)。

cat最好使用内置和sleep或有等效内置命令的shell 。或者在perl/ python...中执行

例如, in ksh93,sleep默认情况下是内置的,cat可以使用 启用内置函数builtin cat。在 中zsh,您可以使用sysreadin 循环代替catzselect代替sleep

zmodload zsh/zselect
zmodload zsh/system
readall() while sysread -s 65536 -o1; do continue; done

{
  tail
  while readall; do
    zselect -t 100
  done
} < /tmp/foo

如果每次都创建一个新文件,tail -f则不会检测到它。如果是这种情况,您仍然可以通过执行以下操作来做到这一点:

#! /bin/zsh -
zmodload zsh/zselect
zmodload zsh/system
readall() while sysread -s 65536 -o1; do continue; done

file=${1-/tmp/foo}
{
  tail
  (( offset = systell(0) ))
} < $file || exit
while true; do
  if
    sysopen -ru0 -- $file 2> /dev/null &&
      sysseek $offset &&
      readall
  then
    (( offset = systell(0) ))
  fi
  zselect -t 100
done

我们重新打开文件并在每次迭代时查找最后一个已知的偏移量。

相关内容