微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

linux – 在运行时替换shell脚本

我有一个运行“补丁”脚本的电路板.补丁脚本始终在后台运行,它是一个运行以下伪代码shell脚本:

while true; do
    # checks if a patch tar file exists and if yes then do patching
    sleep 10
done

此脚本位于/opt/patch.sh,它由SystemV init脚本启动.

问题是,当脚本找到tar时,它会提取它,并且里面有一个名为patch.sh的shell脚本,它特定于tar的内容.

当/opt/patch.sh中的脚本找到tar时,它会执行以下操作:

tar -xf /opt/update.tar -C /mnt/update
mv /mnt/update/patch.sh /opt/patch.sh
exec /opt/patch.sh

它将替换为另一个脚本并从同一位置执行它.
这样做会出现任何问题吗?

解决方法:

如果通过就地写入来替换文件(inode保持不变),那么打开它的任何进程都会在从文件读取时查看新数据.如果通过取消链接文件并创建具有相同名称的新文件来替换它,则inode编号会更改,并且保持文件打开的任何进程仍将具有旧文件.

mv可能会执行任何操作,具体取决于文件系统之间是否发生移动…要确保获得全新文件,请先取消链接重命名原始文件.像这样的东西:

mv /opt/patch.sh /opt/patch.sh.old     # or rm
mv /mnt/update/patch.sh /opt/patch.sh

这样,即使在移动之后,正在运行的shell仍将具有旧数据的文件句柄.

也就是说,据我所测试,Bash在执行任何循环之前读取整个循环,因此只要执行保持在循环内,对底层文件的任何更改都不会更改正在运行的脚本.退出循环后,Bash从循环结束后的位置继续读取输入文件.我不确定读取完整循环是否只是为了它可以检查语法(它可能缺少最后完成),或者它是否用于缓存目的.

脚本中定义的任何函数也会加载到内存中,因此将脚本的主要逻辑放到一个函数中,只在末尾调用它会使脚本非常安全,不会对文件进行修改

#!/bin/sh
main() {
    do_stuff
    exit
}
main

无论如何,测试脚本被覆盖时会发生什么并不难:

$cat > old.sh <<'EOF'
#!/bin/bash
for i in 1 2 3 4 ; do
        # rm old.sh
        cat new.sh > old.sh 
        sleep 1
        echo $i
done
echo will this be reached?
EOF
$cat > new.sh <<'EOF'
#!/bin/bash
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
EOF
$bash old.sh

随着rm old.sh注释掉,脚本将就地更改.如果没有评论,将创建一个文件.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐