【问题标题】:tail -F without interruptionstail -F 不打断
【发布时间】:2017-05-10 06:14:52
【问题描述】:

我正在跟踪一个文件。我想在跟踪文件时从文件中删除行。我想避免覆盖文件(截断)并且我想避免用新文件替换文件,因为这很可能会弄乱/破坏 tail 命令结果。

目前我尝试了两种不同的方法:

  1. 读取文件的全部内容,删除不需要的数据行,然后用比以前更少的数据写回文件。这会导致从 tail 命令喷出一些 stderr => "file was truncated"...tail -F 仍在工作,但它确实记录了这个 stderr。

  2. 使用sed -i '/pattern/d' my-file.txt 从文件中删除我不再需要的行。这会导致从 tail 命令喷出一些 stderr => "file was replaced"(注意与上面不同)...tail -F 仍在工作,但它确实记录了这个 stderr。

我想知道是否有一种方法可以在不截断文件或替换文件的情况下从文件中删除行,因为这似乎让 tail 的生活比其他方式更难。

我应该忽略这个标准错误吗?如果我只是忽略标准错误,我认为尾部结果将不准确。我需要尽可能准确的尾部结果,因为它们正在输入一个新程序,而不是被人类读取。

【问题讨论】:

  • 有没有考虑重定向stderr,也就是tail -F path 2>/dev/null
  • 我认为不可能就地编辑文件。
  • 好吧 sed -i 是 sed --in-place,这似乎背叛了文件实际上被新文件替换的事实,相当蹩脚的 IMO
  • 您真的需要编辑文件还是在拖尾时看不到“坏行”就足够了?
  • @andreas,多个进程将拖尾此单个文件,因此此文件需要是唯一且最终的事实来源。最好只删除行然后修改行并以某种方式将它们标记为“已删除”。如果您不删除行,则文件之夜会变得太大。

标签: linux bash sed


【解决方案1】:

我看到的一种解决方法是:

  • 以读/写方式打开文件
  • 确定要删除的行
  • 不要删除它,而是用空格字符替换前一个换行符+该行的内容。

更换前:

aaaaaaa\n
bbbbbbb\n
ccccccc\n

更换后:

aaaaaaa        \n
ccccccc\n

从视觉上看,日志已删除该行。

如果您不介意多余的空格/可以使用sed 's/ *$//g' 执行离线清理,那很好,因为以读写方式打开不会更改未更改数据或文件节点的位置。

另外,这非常快,因为即使文件很大,您也只是更改几个字节,而不是重写整个文件。

我很难编写这个可行的 python 实现:

import re,os,sys
logfile = sys.argv[1]
regex = sys.argv[2]
replacement_char = " "  # default: space
if len(sys.argv)>3:
   replacement_char = sys.argv[3][0]  # first char of 3rd arg

pattern = re.compile(regex)

with open(logfile,"r+") as f:
    while True:
        old_offset = f.tell()
        l = f.readline()
        if not l:
            break
        if pattern.search(l):
            # match: blank the line
            new_offset = f.tell()
            if old_offset > len(os.linesep):
                old_offset-=len(os.linesep)
            f.seek(old_offset)
            f.write(replacement_char*(new_offset-old_offset-len(os.linesep)))

使用方法:

blank.py logfile regex <optional replacement char>

它是如何工作的:

  • 以读/写模式打开文件
  • 行上的循环
  • 存储当前文件偏移量
  • 读一行
  • 如果匹配正则表达式,获取当前偏移量,倒回到前一个文件偏移量并写入指定的适当数量的空白/替换字符,删除前一个换行符,使空白位于有效行之后,因此在视觉上它与行已被删除。
  • 由于文件以读/写模式打开,读取它的外部程序(在 Linux 上)不会注意到更改,因为大小和 inode 没有改变:tee 没有更多警告

由于它会覆盖前一个换行符,它只是在前一行添加空格/替换字符。

您已经注意到的唯一问题是,如果第一行匹配,那么它将替换字符放入其中。这是它唯一可见的时间。作为一种解决方法,您可以使用特殊的、不可匹配的标头开始您的日志文件。

【讨论】:

  • 我喜欢这个,我希望它有效!您能否逐字引用您建议的 sed 命令将实际编辑文件?
  • 这样做的好处是文件具有相同数量的字符和行,只是现在有些是空格。这将使 tail 命令的工作更轻松!
  • 我看到的唯一问题是,我还想使用 head 命令从文件中读取前几行。如果我有很多空格,那么前几行可能是空的。
  • @JF,我还是不知道用什么命令来做:“与其去掉,不如把前面的换行符+行的内容换成空格字符。”我试过这个答案stackoverflow.com/questions/11245144/…,它也只是用一个新文件替换了文件,所以这对我来说不太好。
  • 谢谢,不过我的猜测是,当你写回文件时,它会截断整个文件并用新结果覆盖。
猜你喜欢
  • 1970-01-01
  • 2015-08-03
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
相关资源
最近更新 更多