我在 bash 脚本中有一个 while 循环:
例子:
while read LINE
do
echo $LINE >> $log_file
done < ./sample_file
我的问题是为什么当我在脚本运行时删除 sample_file 时,循环并没有结束,而且我看到 log_file 正在更新?没有输入时循环如何继续?
我在 bash 脚本中有一个 while 循环:
例子:
while read LINE
do
echo $LINE >> $log_file
done < ./sample_file
我的问题是为什么当我在脚本运行时删除 sample_file 时,循环并没有结束,而且我看到 log_file 正在更新?没有输入时循环如何继续?
在 unix 中,直到文件的最后一个目录条目被删除(例如使用rm
)并关闭它的最后一个打开文件句柄,文件才真正被删除。有关更多信息,请参阅此问题(尤其是 MarkR 的答案)。对于您的脚本,该文件作为循环的标准输入打开while read
,并且直到该循环退出(或关闭其标准输入),rm
该文件实际上不会将其从磁盘上删除。
如果你愿意,你可以很容易地看到这种效果。打开三个终端窗口。首先,运行命令cat >/tmp/deleteme
。第二步,运行tail -f /tmp/deleteme
。第三,在运行其他两个命令后,运行rm /tmp/deleteme
. 此时,文件已被取消链接,但cat
和tail
进程都有打开的文件句柄,因此它实际上并没有被删除。您可以通过在第一个终端窗口(正在运行)中键入来证明这一点cat
,每次点击返回时,tail
都会看到新行添加到文件中并显示在第二个窗口中。
在您结束这两个命令之前,该文件实际上不会被删除(Control-D will end cat
,但您需要 Control-C to kill tail
)。
请参阅“为什么在 unix 中删除后可以访问文件?” 以获得对您在此处观察到的内容的出色解释。
简而言之...
底层 rm 和任何其他可能会删除文件的命令是系统调用 unlink。它被称为取消链接,而不是删除或删除文件或类似的东西,因为它不会删除文件。它删除了一个链接(又名目录条目),该链接是文件和目录中的名称之间的关联。
您可以使用该函数truncate
销毁实际内容(或者shred
如果您需要更安全),这将立即停止示例循环的执行。
在shell执行while循环的那一刻,sample_file
内容已经被读取,在那之后文件是否存在都没有关系。
测试脚本:
$ cat test.sh
#!/bin/bash
while read line
do
echo $line
sleep 1
done < data_file
测试文件:
$ seq 1 10 > data_file
现在,在一个终端中运行脚本,在另一个终端中,您去删除文件data_file
,您仍然会看到脚本打印的 1 到 10 个数字。