![如何在不丢失最近的日志的情况下截断日志文件大小?](https://linux22.com/image/777507/%E5%A6%82%E4%BD%95%E5%9C%A8%E4%B8%8D%E4%B8%A2%E5%A4%B1%E6%9C%80%E8%BF%91%E7%9A%84%E6%97%A5%E5%BF%97%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E6%88%AA%E6%96%AD%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E5%A4%A7%E5%B0%8F%EF%BC%9F.png)
我想将日志文件大小减小到特定的最小大小
我尝试了下面的截断命令
$ 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
选项。