2014-01-13 35 views

回答

1

壳加载脚本到存储器,并产生一个单独的过程,所以旧脚本将继续运行未修改

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

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

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

+1

一般的好建议,但似乎并不能保证bash会预先读取*整个*原始文件;相反,它似乎以固定大小的块读取脚本 - 请参阅http://stackoverflow.com/a/20722200/45375。因此,被覆盖的内容*可能会被执行。 – mklement0

6

bash一般会这么做不是提前加载整个脚本,因此覆盖脚本会产生不可预知的后果。例如,我刚刚创建了一个包含以下内容的脚本:

#!/bin/bash 
echo start old file 
sleep 20 
echo end old file 

...并运行它。

#!/bin/bash 
echo started new file 
sleep 20 
echo end new file 

在此输出所得:

$ ./test.sh 
start old file 
./test.sh: line 4: 0: command not found 
end new file 

事情是这样的bash已通过“休眠20 \ n”行中读取(尽管它正在睡觉,我这个稍微不同的脚本可以覆盖它包括终止换行的行)。在此之后继续,它从文件中的下一个字节位置读取下一个命令,并且由于第二行已经增加了两个字节(“开始” - >“开始”),所以它读完了最后两个新睡眠行的字节(“sleep 20 \ n” - >“0 \ n”),尝试执行“0”作为命令,并且出现错误。然后它运行新内容的最后一行。很凌乱,对吧?

幸运的是,有一种方法来强制bash整个脚本加载到内存中,这样就不会感到困惑,如果它得到改变运行时:

#!/bin/bash 
{ 
    echo start old file 
    sleep 20 
    echo end old file 
    exit 
} 

{迫使外壳至少通过阅读匹配}为了正确解析命令,然后exit确保它永远不会尝试执行任何在}之后添加的内容。我正在测试这与bash版本3.2.48(1) - 释放(在OS X 10.8.5);其他版本可能会有不同的行为...

更新:其他版本的行为确实有所不同。我使用4.3.0(1)版本(在NetBSD 6.1.4下)尝试了相同的测试,并在文件内容被替换后继续运行旧代码。显然它现在将文件缓存在8KB块中(请参阅this unix.se answer)。

+0

我更喜欢这个答案。 – Donovan