在Linux中使用时清空文件

20

我正在尝试在linux下清空一个正在使用中的文件,这是一个日志文件,所以它会持续写入。目前我已经使用了以下命令:

echo -n > filename
或者
cat /dev/null > filename

但所有这些都会生成一个带有换行符(或者我在 vi 中看到的奇怪字符,如^@ ^ @ ^ @ ^ @ ^ @ ^ @ ^ @ ^ @ ^ @ ^ @ ^ ..)的空文件,并且我必须使用 vi dd 手动删除第一行,然后保存。

如果我不使用 vi dd ,则无法使用 grep 操纵文件,但我需要一个可以写入shell脚本的自动过程。

有什么想法吗?


为什么你看到的是“^@^@^@^@”,但你要写成“@@@@”? - glglgl
最终我通过Web服务器使用logrotate回调解决了这个问题。 - Miro Barsocchi
这是错误的,echo -ncat /dev/null都没有向您的文件插入任何换行符。 - Campa
6个回答

25

这应该足以清空文件:

> file

然而,你所说尝试的其他方法也应该可以工作。如果你看到了奇怪的字符,那么它们是被其他东西写入文件的 - 很可能是记录日志的进程。


22
正在发生的事情很简单:您正在清空该文件。
那么,为什么里面充满了 `^@` 呢?实际上它并没有。它有一个“空洞”。
写入该文件的程序使用了 `O_WRONLY`(或者可能是 `O_RDWR`),但是没有使用 `O_APPEND`。在您使用 `cp /dev/null filename` 或 `: > filename` 等类似命令清空该文件时,该程序已经将65536字节写入该文件。
现在该程序要写入另一块数据(比如4096或8192字节)。这些数据将写入哪里呢?答案是:“写入底层文件描述符上的当前寻址偏移量”。如果该程序使用了 `O_APPEND`,那么该 `write` 实际上会被一个 `lseek` 调用所前置,该调用会将当前位置指向“当前文件末尾”即“当前文件长度”。当您截断该文件时,“当前文件末尾”就变成了零(即文件为空),因此 seek 会将 write offset 移动到位置0,并将数据写入那里。但是该程序没有使用 `O_APPEND`,因此并没有“重定位”操作,在当前偏移量处写入数据字节(我们已经声称这个偏移量是65536)。您现在拥有的文件,在0到65535字节偏移量中没有任何数据,紧接着在65536到73727字节偏移量中包含一些数据(假设write写入了8192字节)。那些“缺失”的数据就是文件中的“空洞”。当其他程序试图读取该文件时,操作系统会假装在那里有数据:所有零字节数据。
如果执行write操作的程序不在块边界上执行,则操作系统将实际分配一些额外的数据(以适应将写入整个块中)并将其清零。这些零字节不是“空洞”的一部分(它们是文件中实际的零字节),但是对于不会窥视幕布背后的巫师的普通程序来说,“空洞”零字节和“非空洞”零字节是无法区分的。
您需要做的是修改程序以使用O_APPEND,或者使用诸如syslog之类的库例程,这些例程知道如何与日志轮换操作协作,或者两者都要使用。
[编辑添加:不确定为什么这突然出现在首页上,我回答了一个2011年的问题...]

1
这应该被接受为答案,因为它是最完整和正确的! - pgl

7
另一种方法如下所示:
cp /dev/null the_file

这种技术的优点在于它只需要一个命令,因此如果需要sudo访问,则只需要一个sudo调用。

4

为什么不直接使用:>filename

(:是bash内置命令,与/bin/true具有相同的效果,两个命令都不会输出任何内容)

它可以工作的证明:

fg@erwin ~ $ du t.txt
4       t.txt
fg@erwin ~ $ :>t.txt
fg@erwin ~ $ du t.txt
0       t.txt

1
“:”不是“/bin/true”的别名。在bash中,它是一个空命令-它什么也不做。但是它总是返回true。这里实际上也是不必要的-你可以直接使用“>文件”。 - pgl
@pgl 是的,在bash中它是内置的,我真正的意思是它可以替代/bin/true。重新表述一下... - fge
1
相同的行为。第一次进程写入文件时,它会写入@@@@@@@字符。 - Miro Barsocchi
@MiroBarsocchi,这意味着程序在写入之前会执行seek()操作,它实际上并不填充文件(你看到的@是零)。 - fge
@fge 您所说的“^@”是指零吗?我不知道这是什么时候写的,有时只需使用“:>文件名它”即可正常运行,但有时会出现“^@”。基本上,当我遇到“^@”时,我无法对文件使用GREP。 - Miro Barsocchi

3
如果这是一个日志文件,那么正确的做法是使用logrotate。正如您所提到的手动操作无效。

0

我这里没有Linux shell来尝试,但你试过这个吗?

echo "" > file

是的,与echo -n > filename具有相同的行为,但是会带有换行符。无论如何,在文件开头都会有相同的奇怪字符。 - Miro Barsocchi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接