如何在不丢失最近的日志的情况下截断日志文件大小?

如何在不丢失最近的日志的情况下截断日志文件大小?

我想将日志文件大小减小到特定的最小大小

我尝试了下面的截断命令

$ truncate -s 20M log filename

但当我检查截断的文件时,它会截断最近的日志并保留旧日志

进一步分析后,我发现了 tail 和 head 命令。但问题是,当我使用 head 命令时,它正常工作,而当我使用 tail 命令时,它会以人类不可读的格式保存内容,例如@@@@@@@@@@@

$ head -c 10M logfile > newfile(它保存了文件头部提到的大小)

$ tail -c 10M logfile > newfile(保存了无法读取的内容)

现在我想截断大文件,只删除文件的开头,而不删除文件的结尾,如果可能的话,应该在一个命令中,而不创建另一个文件作为头和尾。有人可以指导我吗?谢谢!

答案1

作为简单性和高可维护性的粉丝,我制作了这个。我愿意听取您的意见。

此命令将截断日志文件/tmp/myfile,它会截断文件的开头而不是结尾,它不需要您配置服务和安装多行脚本;您只需将一行命令添加到您的 crontab 中即可。

tail -c 1M /tmp/myfile > /tmp/dzqxH4ZMiSQb91uMMMgPhsgmpnc && rm /tmp/myfile && mv /tmp/dzqxH4ZMiSQb91uMMMgPhsgmpnc /tmp/myfile

第一个命令将目标文件的 1MB 剪切为一个临时文件,第二个命令删除目标文件,第三个命令将 1MB 的临时文件重命名为目标文件。

它的缺点是它会在您的文件系统中临时分配 1 MB 的空间。如果您想保留日志文件的最后 1 GB,而您的存储空间太小或太慢,这可能会成为一个问题。

如果你的情况是这样的,你可以尝试这个:

fallocate -c -o 0 -l 1M file

它会从文件中截取字节;从位置 0 开始,它会从文件中释放 1 MB 的磁盘空间。我知道它会在原地执行此操作,而不是将数据复制到临时文件中。但这需要更多的复杂性;您需要先计算文件的当前大小才能知道要释放多少空间,或者做一个小循环,例如:

while (file larger than 100M) fallocate 1M; 

生成一个大小在 100 MB 到 99 MB 之间的文件。但我喜欢简单,所以现在我选择第一个选项。

答案2

方法:tail -c 10M logfile > newfile 应该有效。尝试“which tail”和“where tail”来查看哪里出了问题。

我已经使用 tail -c 很多年了。由于这对我来说越来越重要,我刚刚编写了一个小 tcsh 脚本来执行它:

#!/bin/tcsh -f
set echo_style='none' ; setenv LC_ALL C #; set echo verbose

# Purpose: reduce the size of log file FILE to SIZE, if it exceeds
#          twice that amount, by junking the beginning of it.

# Usage: reducelog SIZE FILE
# Clobbers FILE.tmp

# check arguments
set msg="Usage: reducelog SIZE FILE"
if ($#argv != 2) goto err
set size="$1"
set msg="Invalid reduced SIZE"
if (`echo "$size" | grep -c '^[1-9][0-9]*$'` != 1) goto err
set file="$2"
set msg="File not accessible: $file"
if !(-frw "$file") goto err

# check whether we should cut
set msg="Error finding the size of $file"
set oldsize="`ls -l "$file"  | cut -d' ' -f 5`"
if ($status) goto err
if (`echo "$oldsize" | grep -c '^[0-9][0-9]*$'` != 1) goto err
@ maxsize = $size + $size
if ("$oldsize" < "$maxsize") goto end

# cut it down quickly (so that hopefully nothing else interferes)
set msg="Error reducing the size of $file"
tail -c "$size" "$file" >! "$file.tmp"
if ($status) goto err
set msg="Error replacing $file"
mv -f "$file.tmp" "$file"
if ($status) goto err

# check that we did reduce the size
set msg="Error finding the new size of $file"
set newsize="`ls -l "$file"  | cut -s -d' ' -f 5`"
if ($status) goto err
if (`echo "$newsize" | grep -c '^[0-9][0-9]*$'` != 1) goto err
set msg="Failed to reduce the file size"
if !("$newsize" < "$oldsize") goto err

# done
goto end

# error
err:
echo "*** $msg\!"
exit 1

# end
end:

我仍在谷歌搜索这个问题的原因是,我有点担心,当我将日志文件移动到位时,某个进程可能会写入日志文件。但我猜在网上根本找不到其他方法。

注意:在上面的脚本中,SIZE 以字节为单位,例如 100 kB 为 100000。

答案3

配置 logrotate 来管理您的日志文件。

你最可能想要的是copytruncate选项。

相关内容