覆盖执行bash脚本文件

use*_*975 3 bash

如果执行的bash脚本文件被覆盖会发生什么?它会继续执行旧文件还是覆盖文件?

例如/etc/test.sh具有以下内容

cp /test.sh /etc/test.sh

Gor*_*son 10

庆典一般不会提前加载整个脚本,因此可以写剧本能有不可预知的后果.例如,我刚刚创建了一个包含以下内容的脚本:

#!/bin/bash
echo start old file
sleep 20
echo end old file
Run Code Online (Sandbox Code Playgroud)

......跑了 在它睡觉的时候,我用这个略有不同的脚本覆盖了它:

#!/bin/bash
echo started new file
sleep 20
echo end new file
Run Code Online (Sandbox Code Playgroud)

导致此输出:

$ ./test.sh 
start old file
./test.sh: line 4: 0: command not found
end new file
Run Code Online (Sandbox Code Playgroud)

发生了什么事情是bash在睡觉之前读过"睡20"线(包括终止换行的行).当它继续之后,它从文件中的下一个字节位置读取下一个命令,并且由于第二行已经长了两个字节("开始" - >"开始"),它最后读取了最后两个字节新的睡眠行("睡眠20 \n" - >"0 \n"),尝试执行"0"作为命令,并收到错误.然后它运行新内容的最后一行.很乱,对吧?

幸运的是,有一种方法可以强制bash将整个脚本加载到内存中,这样如果在运行时它被改变就不会混淆:

#!/bin/bash
{
    echo start old file
    sleep 20
    echo end old file
    exit
}
Run Code Online (Sandbox Code Playgroud)

{外壳通过匹配至少阅读的力量},以便正确解析命令,并且exit然后确保它永远不会尝试执行被之后添加任何东西}.

顺便说一下,我用bash版本3.2.48(1)-release(OS X 10.8.5)测试了这个; 其他版本可能表现不同......

更新:其他版本确实表现不同.我尝试使用版本4.3.0(1)-release(在NetBSD 6.1.4下)进行相同的测试,并在文件内容被替换后继续运行旧代码.显然它现在以8KB块缓冲文件(请参阅此unix.se答案).

  • 在 Linux 上的 bash 5..0.3(1)-release 下,它读取 8KB 块...但这并不能防止错误(在没有 {} 的版本中),因为在睡眠完成后,它在睡眠后立即返回到文件中的位置!奇怪的行为。{} 仍然保护它,很好的答案。 (3认同)

Don*_*van -1

shell 将脚本加载到内存中并生成一个单独的进程,因此旧脚本将继续运行而不进行修改。

显然,如果您尝试重新运行它,您将获得新版本。

如果您尝试在运行时引入一些新功能,我建议写入临时文件,然后使用 或$()``(反引号)语法执行该文件以生成新进程。

或者,您可以使用它exec来完全替换当前正在运行的程序。