假设我有一个脚本script.sh
,执行需要一些时间。我执行它。./script.sh
当它在终端窗口中运行时,我修改了文件script.sh
。这会对已经运行的进程产生影响吗?
修改后,我执行修改后的文件,所以现在有两个正在运行的进程。这样可以吗?
答案1
更新: 感谢注册用户向我指出 Unix.stackexchange.com 上的更好的答案。
根据脚本的大小和编译器/解释器,脚本会部分/完全加载。因此,如果脚本未完全加载,则脚本的一部分加载到内存后,您对脚本所做的更改将反映在正在运行的实例上。
因此,由于输出不可预测,不建议在当前正在运行的磁盘上更改脚本:首先停止正在运行的实例,然后修改脚本,然后重新执行脚本。
初始答案:当您对脚本进行更改时,您会在磁盘(硬盘 - 永久存储)上进行更改;当您执行脚本时,脚本会被加载到您的内存(RAM)中。
因此,您对脚本所做的更改不会影响正在运行的脚本,它将运行您在进行这些更改之前执行的版本。
但是,当您再次执行更改的脚本而不终止先前运行的实例时,脚本将会有两个实例 - 一个包含更改,另一个包含旧实例。
请注意,脚本使用和修改的资源会发生冲突。例如,如果您正在使用该脚本修改文件,则稍后运行的脚本将无法打开该文件进行写入,从而无法正确执行。
答案2
这需要更新,以上答案现在仅部分正确:
使用当前版本的 bash,在脚本运行时修改磁盘上的脚本将导致 bash“尝试”将更改加载到内存中并在正在运行的脚本中应用这些更改。如果您的更改位于当前正在执行的行之后,则将加载并执行新行。但是,这只是 bash 的猜测,它可能正确也可能错误。
更好的方法是按照以下步骤操作:1)将脚本加载到内存中2)从磁盘中删除脚本3)首先删除磁盘版本,将新脚本写入磁盘,内存版本将失去与它的链接,这样当您在步骤3中提供新版本时,bash 不会尝试将新内容加载到内存版本中。
答案3
我将补充一些我认为其他答案没有提到的东西。很大程度上取决于如何您编辑该文件。echo "stuff" >file
我认为从 shell(另一个实例)执行确实会覆盖该文件。但是如果您使用例如编辑文件emacs
然后保存,则不会发生这种情况。相反,编辑器会将旧文件重命名为某个备份名称(可能实际上是删除了之前的备份),然后将其修改后的缓冲区内容写入新的文件(现已释放)旧名字. 由于读取脚本的 shell(或其他解释器)几乎肯定只会打开文件一次,因此此后它与文件的下落无关姓名,它只是继续读取与打开时文件名关联的物理磁盘文件(由 inode 编号标识)。因此,即使它以块的形式读取脚本(如果使用缓冲文本 I/O,这将是最简单的解决方案),它仍将继续从文件的旧实例中读取行,而这些行很可能不会因您的编辑而改变。
答案4
该 shell 与其他脚本语言不同。
shell 逐个读取并执行命令,因此简单的答案是“是的,编辑正在运行的脚本会影响它”,但了解细节很重要。
如果您很细心,您可以在正在运行的脚本末尾添加行,它们将在脚本中已有的其他命令之后运行。
echo "echo 'This extra command will also run.'" >> yourscript.sh
有些编辑器可能会写入一个与旧文件同名的新文件(inode);这样所做的任何更改都不会影响 shell 读取的内容(这就是这些编辑器这样做的原因)。因此,一些测试尝试会受阻。
但只要你仍然在处理相同的 inode,正在运行的 shell将要如果脚本的改变超出了它所读取的范围,则会受到影响 - 除非它exit
在此之前调用。
读取通常以 4KiB 块为单位进行,因此小脚本可能看起来不受影响,但当它接近文件末尾时,shell(与所有文本处理程序一样)将读取它能得到的任何内容。这种“短读取”本身并不表示文件末尾,shell 将继续读取,直到它读不到任何字节。因此,如果文件在 shell 读取时变长,shell将要读取新数据。
此时需要注意的是,shell 不会尝试读取更多数据,除非它需要完成复合命令的解析,或者因为它只是运行了所有先前的命令。这种延迟是您有机会修改包含脚本的文件的时间。
因此,任何使文件更长几乎总会产生一些影响。
编辑文件并插入否中间的字节将重新定位最后一个否文件的字节刚好超出文件末尾的位置。那些字节将被 shell 读为“新的”,即使它刚刚在它们之前的位置读取它们。
更复杂的是,由于块和行的边界可能不一致,shell 可能会从行的一部分开始读取,从而产生“乱码效果”。如果您添加或删除shell 已读取到的行之前的行。