【问题标题】:Why doesnt "tail" work to truncate log files?为什么“tail”不能截断日志文件?
【发布时间】:2009-11-18 22:03:51
【问题描述】:

我正在尝试使用 cron 脚本管理我的日志文件大小。我基本上想每天晚上删除日志文件的最后 2000 行以外的所有内容。我正在尝试运行此命令,但它似乎是在清空整个文件而不是做我想做的事:

tail -2000 logfile.txt > logfile.txt

有谁知道为什么这不起作用和/或如何完成我想要的?谢谢!

【问题讨论】:

标签: ubuntu


【解决方案1】:

tail 甚至开始读取文件之前,您正在覆盖该文件。 shell 通过首先清除文件来处理> 重定向运算符。然后它运行tail,它没有要读取的数据。

您可以通过使用临时文件来解决此问题:

tail -2000 logfile.txt >logfile.tmp
mv logfile.tmp logfile.txt

【讨论】:

  • > logfile.txt - 表示创建新文件
  • 是的,但如果文件名与输入相同,它将覆盖它
  • 这仅在写入日志文件的进程关闭其文件描述符时才有效。典型,但并非总是如此。
【解决方案2】:

这是另一种解决方案,不处理 tmp 文件:

echo "`tail -2000 logfile.txt`" > logfile.txt

【讨论】:

  • 我遇到的问题是我试图截断带有打开文件描述符的文件。所以 tmp 文件不是一个选项。谢谢!
  • 哟!这是太棒了。您应该添加一些关于为什么这样做的上下文。我假设这是因为反引号首先被处理,它排序“存储”命令中的最后 2000 行,然后被回显并替换 logfile.txt。类似于使用变量,但要简单得多。整洁!
【解决方案3】:

接受的解决方案有问题如果进程保持日志文件打开;您基本上需要重用 i-node。 Mmrobins 的反应不错,logrotate 应该做对了。

要使用 tail,您可以做一些事情(类似于 Pantonza 的 & Greg 的想法),但通过原地截断原始文件来保留原始文件:

tail -2000 logfile.txt >logfile.tmp
cat logfile.tmp > logfile.txt
rm logfile.tmp

为了避免临时文件,你可以读入一个变量,然后把它塞回去:

bash -c 'X=$(tail -2000 logfile.txt);echo "$X">logfile.txt'

在所有情况下,您的截断和附加到文件的进程之间都可能存在竞争条件。不确定 logrotate 是否能解决这个问题,这里的 tail 解决方案都没有。

【讨论】:

    【解决方案4】:

    您可能希望考虑使用logrotate 来获得更强大的解决方案,而不是使用您自己的 cron 文件执行此操作。您可以轮换日志、控制将它们保留多长时间、通过电子邮件发送它们、压缩旧日志以及之后运行脚本(如果需要)。

    参见手册页here 或从命令行输入man logrotate

    在 /etc/logrotate.d/ 目录中创建一个新的 logrotate 文件。这是一个例子:

    /var/logs/myapp/logfile.txt {
      # keep the 5 latest rotations of the log 
      rotate 5
      # rotate once the file is bigger than 2k
      size 2k
      # don't error if the file isn't there
      missingok
      # compress rotated (old) log files
      compress
      # set ownership and permissions on the new log file
      create 0640 myuser myuser
    }
    

    【讨论】:

      【解决方案5】:

      如果您是 vim 用户,那么另一种选择是使用 vi 而不是 tail,直接对文件进行操作:

      vi "+execute \"normal! G2000kO\<esc>dgg\"" "+w" "+q" logfile.txt
      

      字符串G2000kO\&lt;esc&gt;dgg 只是您使用vi 执行此操作的键盘输入(必须对转义按钮进行转义)。它使用起来非常直观,涵盖了广泛的用例。

      vi 还可以处理大型 (10+ GB) 文本文件,甚至不会减慢速度,因此这种方法非常健壮。

      【讨论】:

        【解决方案6】:

        Greg Hewgill 是对的,logfile.txt 在tail 可以处理之前被截断。

        尝试:

        tail -2000 logfile.txt > logfile2.txt; rm -f logfile.txt; mv logfile2.txt logfile.txt
        

        【讨论】:

        • 在这种情况下rm 是不必要的,因为mv 将在重命名期间取消链接目标文件。
        • 对...我只是多余:P
        • 这仅在写入日志文件的进程关闭其文件描述符时才有效。典型,但并非总是如此。
        • 这是不正确的,NVRAM。即使进程没有关闭其 FD,它也能正常工作。它确实截断了文件而没有错误。但是记录过程可能不会意识到文件替换,并且记录可能会停止工作,直到重新打开 [新] 文件。
        猜你喜欢
        • 2013-06-26
        • 2010-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-15
        • 1970-01-01
        相关资源
        最近更新 更多