自删除的Bash脚本

14

当 Bash 脚本遇到删除自身的语句时,如何使其继续执行? 例如,当我运行包含如下内容的 test.sh 脚本:

<--some commands-->
rm test.sh
<--some more commands-->

end

脚本会在执行完毕后删除自身。


3
当应用程序被执行时,它的代码会被加载到内存中。你只是在删除磁盘上的文件,这不会影响内存中的代码。 - Felix Kling
1
假定在执行过程中整个脚本被读入内存,所以rm test.sh之后的命令仍然存在于内存中等待执行。 - punkrockbuddyholly
它不会在内存中复制。因此,例如,如果脚本在运行时被修改,它将执行修改。这最近让我头疼。可爱的例子:这个一行脚本将很快填满您的磁盘:'cat $0 >>$0'。 - Ned
2个回答

24

实际上发生的是bash保持文件处于打开状态,因此rm无法停止。

所以rm调用libc函数“unlink()”,该函数将从目录中删除到i-node的链接。这个“链接”实际上是一个包含inode号码的文件名(您可以使用ls -i查看inode号码)。

只要程序仍在使用i-node,它就会继续存在。

您可以轻松地测试此主张,方法如下:

$ echo read a> ni
$ bash ni

在另一个窗口中:

$ pgrep -lf bash\ ni
31662 bash ni
$ lsof -p 31662|grep ni
bash    31662 wmertens  255r   REG   14,2         7 12074052 /Users/wmertens/ni
$ rm ni
$ lsof -p 31662|grep ni
bash    31662 wmertens  255r   REG   14,2         7 12074052 /Users/wmertens/ni
文件即使在ls命令中看不到,但仍然会保持打开状态。 因此,Bash并没有完全读取整个文件 - 直到Bash完成处理后,该文件才真正被关闭。

1
这就是为什么升级程序不应更改现有的可执行文件,而应该取消链接它们,然后重写新版本的原因。 - curiousguy
好的,但如果文件被另一个进程覆盖会发生什么?该文件已被取消链接,因此它算作“空闲空间”,是吗? - Gianluca Ghettini
@G_G 覆盖只是指由文件名命名的目录条目现在链接到另一个 inode。只要原始 inode 没有被 bash 关闭,它就会存在并被 bash 使用。 - w00t

-1
事实上,这种现象是特定于shell(如bash)的,它们会将文件读入内存,然后执行它们。
如果您执行以下命令a.bat: echo Yo1 del a.bat echo Yo2
则会得到以下输出: C:>a.bat
C:>echo Yo1 Yo1
C:>del a.bat 找不到批处理文件。
这符合您的期望 :-)

1
这是错误的;w00t的回答是正确的。我个人见过在bash脚本正在运行时进行编辑会导致错误的结果,这表明文件仍然被打开和读取。 - Kevin Reid

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