你为什么要猫/ dev / null> / var / log / messages`?


77

在此bash脚本示例页面上,作者介绍了以下脚本:

# Cleanup
# Run as root, of course.

cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."

你为什么cat /dev/null要穿什么?我不明白这是什么意思(就像使用while TRUE; sleep 1; elihwfor {some busy program}吗?)。然而作者称其为“没什么异常”。

Answers:


41

通常,cat /dev/null > [something]当您要擦拭文件内容时,要确保对实际文件状态的中断风险绝对为零。文件的内容显然会被cat /dev/null文件本身抹掉,但文件本身(存在并且为文件系统所知)仍将以相同的inode编号,所有权和权限存在。

对于日志文件,可能是该日志文件本身被另一个进程标记为“正在使用”。这样做(例如)rm /var/log/messages && touch /var/log/messages会破坏其他进程,并可能导致正在运行的进程阻塞。意味着某个过程以某种方式被锁定到连接到该文件的特定inode编号,/var/log/messages可能会突然出现恐慌并说:“嘿!/var/log/messages即使文件仍然存在,也发生了什么!更不用说所有权和权限被错误地重新创建的潜在问题。

由于文件使用/状态的不确定性,cat /dev/null > [something]因此希望清除日志但不希望潜在干扰现有进程操作的系统管理员首选使用。

另外,在页面的上下文中,您链接到作者的状态如下:

这里没有什么不寻常的地方,只有一组命令可以从控制台或终端窗口中的命令行逐个调用。将命令放在脚本中的优点远远超出了不必一次又一次地键入它们的范围。

因此,作者提到的“没什么不寻常的”是关于特定bash脚本的整个概念:它只是一组简单的命令,可以从命令行轻松运行,但是放置在文本文件中,避免不得不一遍又一遍地重新输入。


10
@jlliagre唯一保留下来的内容是问题的上下文,该问题的重点在于原始作者为什么会这样做。如果您对消除“神话”抱有极大的热情,请发布答案,该答案提供了原始作者的编码方法的上下文以及您为什么认为可以用其他方法代替的观点。
JakeGould 2014年

7
@jlliagre Cyrus的答案并未解决核心问题,即原始作者为何会使用该方法,也未解释其背后的原因。提到的教程已经很老了并且可以接受。这既不正确,也不会永久保留一个所谓的“城市传奇”。相反,这是一个人编码与另一个人编码的方式。就如此容易。这是一个样式问题,对可靠性或性能没有负面影响。
JakeGould 2014年

3
truncate -s 0会做同样的事情,并减少惯用语。但是,shell程序员是一群保守的人,他们可能会遇到足够老旧或古怪的系统而缺少该命令。
Schwern 2014年

5
@skift cat /dev/null > /foo/bar截断文件;echo "" > /foo/bar截断它,然后写一个换行符。
大卫

2
与rm&touch相比,此方法的另一个优点是维护所有权和权限。
jjmontes 2014年

121

为什么要把/ dev / null放在任何东西上?

您将执行此操作以截断文件内容,同时保持inode完整。除了将文件大小重置为零以外,所有打开该文件以供读取或写入的程序都不会受到影响。

通常会发现一个伪造的替代方法是删除文件,然后再次创建它:

rm file
touch file

或类似的:

mv file file.old
gzip file.old
touch file

问题是这些方法不会阻止在删除时打开已删除文件的任何进程来保持旧文件的写入。原因是在Unix文件系统下,删除文件时,仅将其名称(路径)与内容(索引节点)断开链接。只要有打开进程以供读取或写入的索引节点,它就可以保持活动状态。

这会导致一些负面影响:文件删除后写入的日志会丢失,因为没有直接/便携式的方法来打开已删除的文件。只要进程正在写入已删除的文件,它的内容仍在使用文件系统上的空间。这意味着,如果由于文件正在填充磁盘而删除/创建文件,则磁盘将保持填充状态。解决后一个问题的一种方法是重新启动记录程序,但是对于关键服务,您可能不希望这样做,并且中间日志肯定会丢失。由于创建的文件可能与原始文件具有不同的权限,所有者和组,因此也会产生副作用。例如,这可能会阻止日志分析器读取新创建的文件,或更糟糕的是,阻止日志记录过程写入其自己的日志。

第一种方法cat /dev/null > file正确地实现了目标,尽管有一个顽强的城市传奇,但它的cat /dev/null一部分绝对没有用。它会打开一个伪文件,该伪文件在设计上是空的,无法读取任何内容,最后退出。这样,使用此命令会浪费键击,字节,系统调用和CPU周期,并且可以毫无疑问地通过更快的no-op命令:甚至在大多数Shell中甚至根本没有任何命令来替换它,而无需任何功能更改。

让我尝试用一​​个隐喻来解释无用cat /dev/null。假设您的目标是倒空玻璃杯。

  • 您首先要清除其中的任何液体。这就足够了,并且> file在重定向始终始终被首先处理的事实下,()正是这样做的。

  • 然后,您选择一个空瓶子(/dev/null)并将其倒入空杯子(cat)中。这是毫无意义的一步...

如果您阅读链接文档的末尾,您可能会注意到脚本的增强版本在此行中的注释:

    cat / dev / null> wtmp#   ':> wtmp'和'> wtmp'具有相同的效果。

他们确实有;太糟糕了cat /dev/null被保留在代码中。

这意味着以下代码将适用于所有常见的外壳程序(csh及其sh系列):

cd /var/log
: > messages
: > wtmp
echo "Log files cleaned up."

这将与使用Bourne语法所有贝壳里,比如ashbashkshzsh和喜欢:

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

但是请注意,在古老的POSIX Bourne之前的shell中,任何这些命令(包括cat /dev/null之后仍由仍在运行的shell脚本附加到文件中)都不会截断文件。不是零字节文件,而是一个大小不变的稀疏文件。如果该文件是由某个进程在写入之前寻求其认为是当前位置的位置写入的,则也会发生同样的情况。

还请注意,通常建议截断文件的某些替代解决方案确实存在缺陷。

  • 以下两个只是不起作用。结果文件不为空,但包含一个空行。这样会破坏wtmp存储固定宽度记录的日志文件。

    echo > file
    echo "" > file
  • 下一个基于BSD sh选项的选项是不可移植的,POSIX没有指定任何允许的回显选项,因此您可能最终得到一个包含带有“ -n” 行的文件:

    echo -n > file
  • 通过使用System V sh转义序列不能移植该代码。某些shell将创建一个文件,其中包含带有“ \c” 的行:

    echo "\c" > file
  • 那个人使用了设计用来完成这项工作的命令。使用的问题truncate不是可移植的,因为Unix / Linux系统中可能缺少POSIX未指定的命令。

    truncate -s 0

最后,这里有一些可移植的替代方法,它们可以正常完成工作:

  • 显式打印一个空字符串到文件:

    printf "" > file
  • 使用true严格等同于no-op 的命令,:尽管更易读:

    true > file

1
@JonathanLeffler我相信这是当前所有csh实现的一部分,尽管不一定要记录在案。从Solaris csh 手册页: Null command. This command is interpreted, but performs no action.。在tcsh手册页或原始BSD 中都没有提到相同的内容,csh但是这种语法可能一直有效。
jlliagre 2014年

6
写作的原因之一cat /dev/null是要表达自己的意图。
Davidmh,2014年

1
@Davidmh这将是明智的,但您的陈述不会拒绝事实核对。我可能已经观察了几十年了。当我有机会向作者询问其背后的原因时,我总是得到关于使用/dev/null一种有效的方式来注入零字节的方法的不可靠理论,无论如何,该方法比使用:或不使用任何方法更可靠。在这一页上,赛勒斯的答案简洁但直截了当,票数为零,而杰克·古尔德(JakeGould)质疑这一事实的人是无人驾驶cat /dev/null(请参阅我们的评论)已经至少有四票。
jlliagre 2014年

2
@jlliagre我对shell的了解是非常基础的,所以我可能不是最好的目标人群;但是裸露>:不清楚。我同意由于神话的使用而传播神话,这是一种耻辱。
Davidmh,2014年

4
@Davidmh如果您真的希望在重定向之前明确一些内容,我建议您printf "" > file既可移植(POSIX)又轻便,通常是内置为shell的。
jlliagre 2014年

6

这是将文件缩小到零大小的麻烦方法。

cd /var/log
> messages
> wtmp
echo "Log files cleaned up."

此语法并非在每个Shell中都适用。
reinierpost 2014年

2
正确。该问题仅用“ bash”标记。
赛勒斯2014年

@reinierpost它可以在所有伯恩风格的外壳中使用,不是吗?不用担心csh
Barmar 2014年

: > messages也可以。 :还是true什么都不显示并返回true的命令更明显的选择。
彼得·科德斯

-3

截断打开的文件。这是等效的,并且更易于理解:

echo -n > /var/log/messages

(添加-n以避免换行)


3
这确实是更容易理解的,但不幸的是不是等效的。甚至会破坏功能wtmp。看到我更新的答案。
jlliagre 2014年

echo -n避免换行符。
bbaassssiiee 2014年

6
实际上,如果您确定要使用bash,它将-n不能保证不能在所有Bourne外壳中使用。
jlliagre 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.