服务器跑久了,/var/log 里堆满 access.log、error.log、app.log 之类的文件,动不动就占几个G。手动删?太累;写个 shell 脚本?也行,但 Perl 处理文本和时间逻辑更顺手,尤其适合按日期、大小、匹配模式来精准清理。
一个实用的清理脚本
下面这个 Perl 脚本会遍历指定目录下的所有 .log 文件,只保留最近7天的,超过的直接删除(支持 dry-run 模式预览):
#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;
use Time::Local;
my $log_dir = shift || '/var/log';
my $keep_days = 7;
my $dry_run = 0; # 设为1可先看要删哪些,不真删
opendir my $dh, $log_dir or die "无法打开目录 $log_dir: $!";
while (my $file = readdir $dh) {
next unless $file =~ /\.log(?:\.\d+)?$/; # 匹配 log 或 log.1、log.gz 等常见后缀
my $path = "$log_dir/$file";
next unless -f $path;
my @stat = stat($path);
my $mtime = $stat[9];
my $now = time();
my $age_days = int(($now - $mtime) / 86400);
if ($age_days > $keep_days) {
if ($dry_run) {
print "[DRY-RUN] 即将删除:$file (修改于 $age_days 天前)\n";
} else {
unlink $path or warn "删除失败 $file: $!\n";
print "已删除:$file\n";
}
}
}
closedir $dh;怎么用?
保存为 clean_logs.pl,加执行权限:chmod +x clean_logs.pl
先试运行(只显示不删):perl clean_logs.pl /var/log --dry-run
确认没问题后,去掉 --dry-run 参数或把脚本里的 $dry_run = 1 改成 0,再跑一次就真删了。
还能再灵活点?
比如你只想清 nginx 的 access 日志,且要求文件大于10MB才处理,可以加一行判断:next unless -s $path > 10_485_760;
或者按文件名匹配:next unless $file =~ /^access\.log(?:\.\d+)?$/;
Perl 的正则和文件操作写起来比 shell 更紧凑,改几行就能适配不同项目。
加到定时任务里
编辑 crontab:crontab -e
加一行每天凌晨2点执行:0 2 * * * /path/to/clean_logs.pl /var/log/nginx > /dev/null 2>&1
日志清理这事,设好一次,后面就忘了它——这才是自动化该有的样子。