如何只保留日志文件的最后 n 行?

如何只保留日志文件的最后 n 行?

我编写了一个脚本,该脚本执行某些操作,然后将一些行附加到其自己的日志文件中。我只想保留最后一个n日志文件的行(例如 1000 行)。这可以通过以下方式在脚本末尾完成:

tail -n 1000 myscript.log > myscript.log.tmp
mv -f myscript.log.tmp myscript.log

然而,有没有更干净、更优雅的解决方案呢?也许通过单个命令即可完成?

答案1

这是可能的,但正如其他人所说,最安全的选择是生成新文件,然后移动该文件以覆盖原始文件。

下面的方法将行加载到 BASH 中,因此根据 的行数tail,这将影响本地 shell 存储日志行内容的内存使用量。

下面的内容还会删除日志文件末尾存在的空行(由于 BASH 评估的行为"$(tail -1000 test.log)"),因此不会在所有情况下给出真正 100% 准确的截断,但根据您的情况,可能就足够了。

$ wc -l myscript.log
475494 myscript.log

$ echo "$(tail -1000 myscript.log)" > myscript.log

$ wc -l myscript.log
1000 myscript.log

答案2

该实用程序sponge专为这种情况而设计。如果你安装了它,那么你的两行可以写成:

tail -n 1000 myscript.log | sponge myscript.log

通常,在写入文件的同时读取文件是不可靠的。 通过在完成读取并终止管道之前sponge不写入来解决此问题。myscript.logtail

安装

sponge要在类似 Debian 的系统上安装:

apt-get install moreutils

要在 RHEL/CentOS 系统上安装sponge,请添加 EPEL 存储库,然后执行以下操作:

yum install moreutils

文档

man sponge

sponge读取标准输入并将其写入指定文件。与 shell 重定向不同,sponge在写入输出文件之前吸收所有输入。这允许构建读取和写入同一文件的管道。

答案3

肯定是“尾巴+mv”更好!但对于 gnu sed 我们可以尝试

sed -i -e :a -e '$q;N;101,$D;ba' log

答案4

在 ksh93 shell 中:

$ seq -f 'This is line %g' 10000 > file.log
$ tail -n 5 file.log 1<>; file.log
$ cat file.log
This is line 9996
This is line 9997
This is line 9998
This is line 9999
This is line 10000

就像n<>; file标准的重定向操作符,它以读+写模式n<> file打开fileon fdn没有截断与 with 的区别是<>;,如果重定向的命令成功,则会在命令离开的位置对 fd 执行ksh93隐式操作。ftruncate()

对于其他 shell,您可以执行相同的操作:

{
  tail -n 5 file.log &&
    perl -e 'truncate STDOUT, tell STDOUT'
} 1<> file.log

相关内容