如何截断所有日志文件?

有谁能给我一个截断/var/log/目录下所有日志文件的解决方案吗?
还有一个只是出于知识的问题,这个做法是否明智?
#!/bin/bash
LOGDIR="/var/log"
for logfile in $(ls $LOGDIR/*log)
do
  truncate -s 0 $logfile
done

1这不是一个好主意 - /var/log 是系统存放可能以后会用到的消息的地方。Ubuntu之前遇到过这个问题。阅读 man 8 logrotate;man logrotate.conf - waltinator
5个回答

试一下这个:

truncate -s 0 /var/log/*log

编辑:

如果你想多次执行此操作,你应该使用 logrotate 来处理日志。通常它已经安装在Ubuntu上了。可以查看一下 man logrotate(或者如果你没有安装,可以查看 在线手册 或者使用 sudo apt-get install logrotate 安装)

从手册中可以看到:

logrotate 旨在简化生成大量日志文件的系统的管理。它允许自动旋转、压缩、删除和发送日志文件。每个日志文件可以按天、周、月或大小来处理。


1你也可以通过使用 "echo "" > *log" 来清空它们。 - Astm

如果你想清除所有的日志文件,而不仅仅是一级日志文件夹中的文件,你可以使用以下方法:
shopt -s globstar                  # if needed
truncate -s 0 /var/log/*.log       # first-level logs
truncate -s 0 /var/log/**/*.log    # nested folders, like /var/log/nginx/access.log

请注意,如果您已经在运行logrotate,您还需要清除已经旋转的.gz日志文件。
find /var/log -type f -name '*.[0-99].gz' -exec rm {} +

一个有效的用途可以是构建用于分发的虚拟机容器,例如。
你不应该在例行维护中需要这样做:正如D-E-N所建议的那样,使用logrotate就可以了。

作为对@D-E-N答案的后续,以下是解决方案:
这将在/var/log中找到所有日志文件,并将它们截断为0字节。
find /var/log -type f -iname '*.log' -print0 | xargs -0 truncate -s0

1我会使用*.log*,但我不确定它是否百分之百安全,所以我没有在答案中包含它。因为有像dovecot.log-20180930dovecot.log-20180923.gz这样的文件。 - Luka

将/var/logs中的日志文件进行定期轮转是一个好的实践,可以使用logrotate功能来实现,但不是随时都可以进行。系统日志将在此处打印,并且它们对于调试任何故障非常方便。

如果要求不使用logrotate,则可以探索其他选项。尽管在某些Unix系统的几个版本中,截断是一种简单的选择,但该命令并不容易获得,需要安装。如果不允许安装新命令,则可以使用下面的循环。

for logfile $(ls /path/*.log)
do 
  cat /dev/null > $logfile
done

Bash陷阱#1不要以那种方式编写for循环。 而是使用for logfile in /path/*.log - PerlDuck

有几种方法可以完全截断文件,通常适用于大多数符合POSIX标准的操作系统。你在shell脚本中看到最常见的是像true > file.txt: > file.txt这样的东西(在bash shell的情况下,仅使用>重定向就足够了)。这是因为>通过open()openat()系统调用以O_WRONLY|O_CREAT|O_TRUNC标志打开文件的方式 - 这读取只写OR创建(如果文件名不存在)OR截断现有文件名。

有了这个想法,我们可以自己在C中实现类似的东西:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv){
    if (argc == 2){
        int fd = open(argv[1],O_TRUNC);
        close(fd);
    }

    return 0;
}

将存储此代码的文件命名为trunc.c,并使用gcc trunc.c -o trunc进行编译,这样您就拥有了一个小型实用程序,可以截断作为文件名参数提供的文件名,例如trunc ./foobar.txt。当然,此代码不会进行其他检查,它只会截断第一个位置参数。我将让读者自行解决如何处理多个位置参数的问题。另外,还有truncate()系统调用,我们也可以使用它来将文件截断为可变长度。
现在,如果您不喜欢C语言,Python可能更容易上手。在Python中,open()命令的操作原理与之相同-打开文件以进行写入,并在文件名存在时进行截断。因此,我们可以这样做:
python -c 'import sys;open(sys.argv[1],"w").close()' passwd.copy 

关于查找所有的.log文件,这个问题已经在其他答案中提到了 - 在bash中使用*通配符或扩展通配符。还有一个命令是find -type f -name "*.log",它有一个-exec标志用于运行命令(在这种特殊情况下,使用sh -c ''来利用>,因为>是一个shell操作符而不是外部可执行程序)。因此,你可以这样做
find /var/log -type f -name "*.log" -exec sh -c 'true > "$1"' sh {} \;

值得注意的是,目录中的日志文件(例如/var/log)通常会被logrotate服务进行轮转,因此会出现诸如/var/log/service.log/var/log/service.log.1等文件名,因此您可能希望使用*.log.[1-9]模式。
除此之外,我们还可以将/dev/null复制到所需的文件中。奇怪的是,尽管/dev/null是一个特殊字符设备类型的文件,但当你将其复制到其他地方时,结果是一个空的普通文件,至少在GNU cp中是如此。因此,我们可以这样做:
cp /dev/null foo.txt

或者
dd if=/dev/null of=foo.txt

其他建议阅读:
- [什么是 ">" 和 ">>" 的区别?]({{link1}}) - [Python 的 open 函数文档]({{link2}}) - [如何清理日志文件]({{link3}}) - [清空文件内容]({{link4}})