在这个bash 脚本示例页面上,作者展示了这个脚本:
# Cleanup
# Run as root, of course.
cd /var/log
cat /dev/null > messages
cat /dev/null > wtmp
echo "Log files cleaned up."
Run Code Online (Sandbox Code Playgroud)
你为什么要cat /dev/null
上任何东西?我不明白这里的意图是什么(就像使用while TRUE; sleep 1; elihw
for 一样{some busy program}
?)。然而,作者称其为“没什么不寻常的”。
jll*_*gre 122
你为什么要把 /dev/null 放到任何东西上?
您将这样做以截断文件内容,同时保持 inode 完好无损。除了文件大小将重置为零之外,所有打开该文件进行读取或写入的程序都不会受到影响。
经常发现的一个虚假替代方法是删除文件然后再次创建它:
rm file
touch file
Run Code Online (Sandbox Code Playgroud)
或类似的:
mv file file.old
gzip file.old
touch file
Run Code Online (Sandbox Code Playgroud)
问题是这些方法不会阻止旧文件被在删除时打开已删除文件的任何进程写入。原因是在 Unix 文件系统下,当您删除一个文件时,您只是将其名称(路径)与其内容(inode)断开链接。只要有进程打开它进行读取或写入,inode 就会保持活动状态。
这会导致几个负面影响:文件删除后写入的日志丢失,因为没有直接/便携的方式来打开已删除的文件。只要进程正在写入已删除的文件,其内容仍会占用文件系统上的空间。这意味着,如果您删除/创建文件,因为它已填满您的磁盘,则该磁盘将保持填满状态。解决后一个问题的一种方法是重新启动记录器进程,但您可能不想为关键服务这样做,并且中间日志将最终丢失。由于您创建的文件可能与原始文件具有不同的权限、所有者和组,因此还有一些副作用。例如,这可能会阻止日志分析器读取新创建的文件,或者更糟的是,会阻止日志记录进程写入自己的日志。
第一种方法,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."
Run Code Online (Sandbox Code Playgroud)
这将与使用Bourne语法所有炮弹一样工作ash
,bash
,ksh
,zsh
和喜欢:
cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Run Code Online (Sandbox Code Playgroud)
但是请注意,对于古老的、POSIX 之前的 Bourne shell,这些命令中的任何cat /dev/null
一个都不会截断文件,如果它是由一个仍在运行的 shell 脚本附加到它之后写入的。这将是一个大小不变的稀疏文件,而不是零字节文件。如果文件是由一个进程在写入之前寻求它认为是当前位置的位置写入的,则会发生同样的情况。
另请注意,通常建议截断文件的某些替代解决方案确实存在缺陷。
以下两个都不能完成这项工作。生成的文件不是空的,而是包含一个空行。这会破坏wtmp
存储固定宽度记录的日志文件。
echo > file
echo "" > file
Run Code Online (Sandbox Code Playgroud)
下一个基于 BSDsh
选项的选项不可移植,POSIX 没有为 echo 指定任何允许的选项,因此您最终可能会得到一个包含带有“ -n
”的行的文件:
echo -n > file
Run Code Online (Sandbox Code Playgroud)
通过使用 System Vsh
转义序列,那个也不能移植。一些 shell 会创建一个文件,其中包含一行“ \c
”:
echo "\c" > file
Run Code Online (Sandbox Code Playgroud)
那一个使用旨在完成这项工作的命令。问题是使用truncate
不可移植,因为此命令不是由 POSIX 指定的,可能在 Unix/Linux 系统中丢失。
truncate -s 0
Run Code Online (Sandbox Code Playgroud)
最后,这里有几个可移植的替代方案,可以正确地完成工作:
将空字符串显式打印到文件中:
printf "" > file
Run Code Online (Sandbox Code Playgroud)
使用true
严格等同于 no-op的命令,:
但更具可读性:
true > file
Run Code Online (Sandbox Code Playgroud)
Gia*_*968 43
您通常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 脚本的整个概念:它只是一组简单的命令,可以很容易地从命令行运行,但放在一个文本文件中避免必须一遍又一遍地重新键入它们。
这是使文件大小为零的繁琐方法。
cd /var/log
> messages
> wtmp
echo "Log files cleaned up."
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
33723 次 |
最近记录: |