在 Linux 中如何从文件中删除除最后 n 个字节之外的所有内容?

在 Linux 中如何从文件中删除除最后 n 个字节之外的所有内容?

我有一个 Tomcat 服务器,其中日志存储为catalina.out.这是一个相当大的文件,并且多次造成麻烦。

由于它占用太多空间,其他服务器不得不不由自主地停止。我至少希望用胶带修复此问题,这样我就不必为仅删除catalina.out并重新启动服务器的票证而烦恼。

我不确定,但它的 1 天日志超过 5 GB。所以,假设我想做一个计划任务删除超过一天的文件或该文件中最后 5 GB 的文件。什么命令在这里起作用?

是否建议这样解决这个问题?或者有更好的方法吗?

答案1

catalina.out应该大部分是空的,这意味着应用程序会拦截所有错误并自行处理它们,可能会将它们记录在配置的其他位置。但通常情况下,没有这样做并且catalina.out被认为是应用程序日志。这会导致问题,因为默认情况下 Tomcat 不会轮换该文件。

截断文件的更好方法(除了修复应用程序之外)是对catalina.out.这可能已经由特定的打包安装提供(例如:CentOS7 的 tomcat 7 附带了适当的catalina.out日志轮换),或者使用足够新的 tomcat 版本,如错误 64430谁的使固定已集成到较新的 Tomcat 中,并向后移植到 Tomcat >= 7.0.105、>= 8.5.56 和 >= 9.0.36:

示例(全部一行)

CATALINA_OUT_CMD="/usr/bin/rotatelogs -f $CATALINA_BASE/logs/catalina.out.%Y-%m-%d.log 86400"

旋转文件应进一步处理logrotate或同等的专用工具。

现在严格回答这个问题,或者至少回答有关处理单个文件的部分catalina.out。 OP 都写了:

如何在 Linux 中从文件中删除除最后 n 个字节之外的所有内容?

=> 保留结尾

删除该文件的最后 5GB

=> 保持开始

保持开始

从而去除末端。即使删除结尾日志而不是开始日志是一个坏主意:

POSIXtruncate(2):

姓名

truncate - 将文件截断为指定长度

[...]

描述

truncate() 函数应使由路径命名的常规文件的大小应等于 length 字节。

其中有它的truncate(1)命令实现。为了GNU 截断(沿着 GNU stat(1))将在 shell 中像这样使用(必须首先检查文件是否大于 5GiB,否则其大小将增加)。保留 5GiB:

if [ $(stat -c %s catalina.out) -gt $((5*1024*1024*1024)) ]; then
    truncate -s $((5*1024*1024*1024)) catalina.out
fi

保留结尾

从而删除文件的开头。在 Linux 和足够的文件系统(例如:Ext4、XFS ...)上可以执行此操作,而不涉及任何数据副本,使用fallocate(1)(具有仅限 Linux 的附加功能):

-p,--punch-hole

释放字节范围内的空间(即,创建一个空洞),从 offset 开始,持续 length 个字节。

这不涉及任何数据副本,但需要块对齐(通常为 4096 字节对齐)。人们可以始终保留文件的末尾,有点像环形缓冲区,而无需任何复制成本。可以这样使用(需要额外的计算来对齐 4096 的倍数):


oldsize=$(stat -c %s catalina.out) || exit 1

if [ $oldsize -gt $((5*1024*1024*1024)) ]; then
    holesize=$(( (oldsize-5*1024*1024*1024)/4096*4096 ))
    fallocate --punch-hole --length "$holesize" catalina.out
fi

--punch-hole使用(通过使文件稀疏并保持其表观大小来释放磁盘空间)而不是--collapse-range(将剩余数据“移动”到开头以减少大小)以避免破坏catalina.outTomcat 附加的正在进行的输出,否则应停止 Tomcat之前和之后重新启动。

答案2

tail catalina.out > catalina.new
rm catalina.out
mv catalina.new catalina.out

然后,您必须重新启动或重新加载 tomcat 以将日志附加到新文件(它仍然打开了旧 catalina.out 文件的文件描述符,现已删除)。

tail(从核心工具) 具有以下参数:

-c--bytes=[+]NUM输出最后一个NUM字节;或用于从每个文件的-c +NUM字节开始输出NUM

-n--lines=[+]NUM输出最后NUM几行,而不是最后10行;或用于-n +NUM输出以行开头NUM

其他参数请咨询man tail

答案3

与其治疗症状,不如治疗疾病。

正如其他人提到的,“适当的日志记录”将使您免于这种情况。但正确的日志记录涉及开发团队、开发-测试-发布周期等,您可能想解决您的问题现在

catalina.out填充的原因是因为应用程序正在写入stdout,可能使用System.out.println或类似的。这不太好,应该随着时间的推移而修复。

幸运的是,Tomcat 为您提供了创可贴。您所要做的就是META-INF/context.xml在应用程序中编辑文件(或者,无论您的<Context>定义在哪里,可能在conf/server.xml, 或conf/[engine]/[host]/[app].xml)中,并将其添加到您的<Context>

swallowOutput="true"

搜索https://tomcat.apache.org/tomcat-9.0-doc/config/context.html对于“swallowOutput”请参阅说明。

这将从您的应用程序中获取所有内容并将其放入特定于应用程序的日志文件中,该文件可旋转。

然后,您可以在几天后删除整个日志等,而不是玩尝试“缩短”文件的游戏。

相关内容