安全清理linux日志需先用find按-mtime或-atime筛选旧文件,再用lsof排除正被进程写入的文件,最后rm删除;对journald须用journalctl --vacuum-time,非标路径或特殊策略(如按大小+时间、压缩后通知)才需自定义脚本,并注意crontab中绝对路径与权限。

Linux 上日志清理脚本不能只靠 rm -f 狂删,否则容易误删、漏删、或清理后服务写不进新日志。
怎么安全判断哪些日志该删?
核心是区分「可删」和「正在被进程写入」的日志文件。直接 ls -t | head -n 10 排序后删最老的,风险极高——比如 /var/log/syslog 被 rsyslogd 持续打开写入,删了文件名还在,但磁盘空间不释放(inode 未被回收)。
- 优先用
find按修改时间(-mtime +30)或访问时间(-atime +7)筛选,比单纯按文件名排序可靠 - 用
lsof +D /var/log查看哪些日志正被进程占用,避免对正在写的文件执行rm - 对 systemd-journald 管理的日志,必须用
journalctl --vacuum-time=2weeks,不能手动删/var/log/journal/下的二进制文件
logrotate 配置比手写脚本更稳,什么情况下必须自己写?
当 logrotate 不适用时才动手写:比如非标准路径的日志(/opt/myapp/logs/)、需要按大小+时间双条件清理、或要集成到已有运维流程中触发清理。
- logrotate 默认不处理软链接指向的目录,而自定义脚本可以加
-L参数支持 - logrotate 对压缩后日志的保留策略(如
rotate 5)是固定轮转数,无法表达「保留最近 3GB 总体积」这类需求 - 若需清理前先
gzip再删,或清理后发 Slack 通知,logrotate 插件机制太重,不如 shell 脚本直写postrotate块
一个最小可用的清理脚本长什么样?
以下脚本只做三件事:查旧文件 → 排除正在写入的 → 安全删除,不依赖外部工具(如 dateutils),兼容 CentOS 7 / Ubuntu 20.04+:
#!/bin/bash LOG_DIR="/var/log/myapp" DAYS=30 <h1>找出修改时间早于 $DAYS 天的普通文件(排除目录、符号链接)</h1><p>old_logs=$(find "$LOG_DIR" -type f -mtime +"$DAYS" 2>/dev/null)</p><h1>过滤掉被进程打开的文件(避免删正在写的)</h1><p>safe_to_remove="" while IFS= read -r file; do if ! lsof "$file" >/dev/null 2>&1; then safe_to_remove="$safe_to_remove"$'\n'"$file" fi done </p><h1>真正删除(加 -v 可看过程,上线前建议先注释掉这行,用 echo 测试)</h1><p>if [ -n "$safe_to_remove" ]; then echo "$safe_to_remove" | xargs -r rm -f fi </p>
-
find ... -mtime +30表示「30 天前修改的」,注意不是「30 天内没动过」;如需按最后访问时间删,换-atime -
xargs -r是关键:当safe_to_remove为空时不执行rm,避免rm -f误删当前目录 - 脚本开头务必加
#!/bin/bash,别用#!/bin/sh,否则$(...)和[[语法在某些系统上会失败
定时运行时最容易忽略的权限和路径问题
crontab 里跑脚本失败,90% 出在环境变量和工作目录上,不是逻辑问题。
- crontab 中的
PATH极简(通常只有/usr/bin:/bin),脚本里调用lsof或find必须写绝对路径(/usr/bin/find)或显式设置PATH=/usr/local/bin:/usr/bin:/bin - crontab 默认工作目录是用户家目录,脚本里所有路径必须用绝对路径,
cd /var/log后再操作也不保险 - 用
root用户运行才能删/var/log下多数日志,但不要把脚本权限设成777,chmod 755+chown root:root即可
真正难的是判断「这个日志到底算不算业务关键」——比如某个中间件日志删了不报错,但排查问题时发现 last 2 小时的 trace 全没了。这类边界得结合具体服务文档定,脚本只负责执行规则,不代替人决策。











