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

ach*_*san 3 linux rm files tomcat delete

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

\n

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

\n

我不确定,但它的 1 天日志超过 5\xc2\xa0GB。因此,假设我想做一个cron 作业,删除超过一天的文件或该文件中最后 5\xc2\xa0GB 的文件。什么命令在这里起作用?

\n

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

\n

A.B*_*A.B 5

catalina.out应该大部分为空,这意味着应用程序会拦截所有错误并自行处理它们,可能会按照配置将它们记录在其他地方。但通常情况下,不会执行任何此类操作,并且catalina.out将其视为应用程序日志。这会导致问题,因为默认情况下 Tomcat 不会轮换该文件。

截断文件的更好方法(除了修复应用程序之外)是对catalina.out. 这可能已经由特定的打包安装提供(例如:CentOS7 的 tomcat 7 附带了适当的catalina.out日志轮换),或者使用足够新的 tomcat 版本(如Bug 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"
Run Code Online (Sandbox Code Playgroud)

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

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

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

=> 保留结尾

删除该文件的最后 5GB

=> 保持开始

保持开始

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

POSIX truncate(2)

姓名

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

[...]

描述

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

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

CATALINA_OUT_CMD="/usr/bin/rotatelogs -f $CATALINA_BASE/logs/catalina.out.%Y-%m-%d.log 86400"
Run Code Online (Sandbox Code Playgroud)

保留结尾

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

-p,--punch-hole

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

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

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

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