可以用新版本替换bash脚本会导致脚本的运行实例失败

时间:2011-01-21 01:35:43

标签: bash

我正在从服务器上的java程序运行bash脚本。我刚刚上传了一个新版本的脚本,打算在下一次运行脚本时使用该版本。我并不打算中断现有的,运行的脚本实例。但是,我刚从300台服务器收到100多个崩溃通知。我猜测用新版本替换正在运行的bash脚本导致了这个问题。但是,这将要求运行的bash脚本在进入每个新步骤时从磁盘读取。这是它的工作原理吗?

bash脚本的运行版本运行一些光线跟踪软件。每次运行需要2个小时。子步骤需要5分钟到1.5小时。在脚本中完成一个步骤后,脚本始终报告崩溃。它永远不会报告已经运行的子步骤崩溃。一些崩溃报告没有找到我在脚本中找不到的命令。不同的崩溃报告不同的地方。

帮助!

编辑:我使用scp将脚本复制到所有300台服务器。该文件已在文件系统上替换。这不是共享文件。

4 个答案:

答案 0 :(得分:17)

SiegeX是正确的一半 - bash会将整个脚本加载到内存中,因此即使在进程运行时删除了源文件,脚本也可以继续运行。但是bash还会在脚本运行时检查源文件是否更新。如果是,bash将重新加载并继续从当前位置运行重新打开文件,寻找脚本的当前位置,并从那时起继续运行脚本。

这是一个概念验证脚本:

# If you modify a script, will it change the behavior of
# processes that are currently running that script?
# Does this script print "Foo" or "Bar"?

cat >foo.sh <<EOF
sleep 5
echo Foo
EOF

bash foo.sh &
sleep 2

cat >foo.sh <<EOF
sleep 5
echo Bar
EOF

wait

因此,如果您关心当前运行该脚本的进程,那么结果就是不要修改bash脚本的源文件。


(但是,此脚本显示“Foo”.bash脚本的“当前位置”始终位于行的开头或结尾。)

echo "sleep 5 ; echo Foo" > foo.sh
bash foo.sh &
sleep 2
echo "sleep 5 ; echo Bar" > foo.sh
wait

答案 1 :(得分:1)

如果可以避免,请不要更新正在运行的系统


删除脚本是一回事,但修改它可能会产生更多“有趣”的结果。

此外,更改复制和/或网络安装的文件会引入特定于文件系统和部署协议的行为。这些不会通过对本地硬件安装的简单测试或在读取文件的同一系统上修改网络安装的测试来准确建模。

此外,将此文件“上传”到300台服务器会引入各种奇妙的复杂性,我们溢出的人可能没有足够的信息来分析。

ISTM您的问题可能 与更新有关。我认为神秘命令可能来自bash从旧版本读取部分脚本,从新版本读取部分。我知道如果可能的话,你应该在更新时关闭子系统。

答案 2 :(得分:1)

我不确定自从已经接受了暴徒的回答之后情况是否已经改变,但是在bash 4.3.46(例如ubuntu 16.04附带)中,bash监视脚本文件是否有变化是真的,但是这个如果文件被删除,则会中断。

所以对他的剧本略微修改了“正确”的事情:

# If you modify a script, will it change the behavior of
# processes that are currently running that script?
# Does this script print "Foo" or "Bar"?

cat >foo.sh <<EOF
sleep 5
echo Foo
EOF

bash foo.sh &
sleep 2

rm foo.sh

cat >foo.sh <<EOF
sleep 5
echo Bar
EOF

wait

现在打印Foo

答案 3 :(得分:0)

调用后,bash将分叉一个新进程并将脚本加载到内存中。除非脚本引用自身,否则它仍然可以工作。下面是一个脚本示例,它既可以从磁盘中删除自身,也可以在尝试通过$0

访问自身之前一直工作

输入

#!/bin/bash

echo "I can't take it anymore"
echo "Goodbye World!"

rm -f "$0"

echo "Wait, I change my mind!"

sed 's/Goodbye/Hello/' "$0"

输出

$ ./suicide.sh
I can't take it anymore
Goodbye World!
Wait, I change my mind!
sed: can't read ./suicide.sh: No such file or directory