use*_*910 3 bash shell auto-update
我正在构建一个小脚本来更新树莓派上的应用程序文件。
它将执行以下操作:
我遇到的问题是其中一个文件是 updatescript.sh。
我已经读到在执行时更新/更改 bash 脚本是危险的。请参阅在运行时编辑 shell 脚本
有什么好方法可以实现我想要做的事情吗?
你读到的东西被严重夸大了。
通过在其上覆盖mv不同的文件来就地覆盖 shell 脚本是完全安全的。执行此操作时,旧文件句柄仍然有效,指的是原始未修改的文件内容。您不能安全地做的是就地编辑现有文件。
所以,下面的内容很好(并且是您所有的操作系统供应商更新工具,如 RPM):
#!/usr/bin/env bash
tempfile=$(mktemp "$BASH_SOURCE".XXXXXX)
if curl https://example.com/whatever >"$tempfile" &&
curl https://example.com/whatever.sig >"$tempfile.sig" &&
gpgv "$tempfile.sig" "$tempfile"; then
chown --reference="$BASH_SOURCE" -- "$tempfile"
chmod --reference="$BASH_SOURCE" -- "$tempfile"
sync # force your filesystem to fully flush file contents to disk
mv -- "$tempfile" "$BASH_SOURCE" && rm -f -- "$tempfile.sig"
else
rm -f -- "$tempfile" "$tempfile.sig"
exit 1
fi
Run Code Online (Sandbox Code Playgroud)
...而这是有风险的:
curl https://example.com/whatever >/usr/local/bin/whatever
Run Code Online (Sandbox Code Playgroud)
所以做第一件事,而不是第二件事:下载脚本的新版本时,将其写入不同的文件,只有在下载成功时才将其重命名为原始文件。无论如何,这就是您想要做的以确保原子性。
(上面还有一些代码签名验证实践的演示,因为在构建更新程序时您需要它们。您不会在不验证签名的情况下尝试通过自动下载分发代码,对吧?因为那是多么简单闯入您的 Web 服务器会导致您的每一个客户都被 0wned。上面期望您的代码签名密钥的公共端在 中~/.gnupg/trustedkeys.gpg,但您可以放入trustedkeys.gpg任何目录并使用环境变量指向它GNUPGHOME)。
即使您没有安全地编写更新代码,风险仍然是微不足道的。如果您将脚本的主体移动到一个函数中,以便在执行它的任何部分之前必须完全读取它,那么在执行开始时文件中没有任何部分尚未读取。
#!/usr/bin/env bash
main() {
echo "Logic all goes here"
}; { main "$@"; exit; }
Run Code Online (Sandbox Code Playgroud)
由于{ main "$@"; exit; }是复合命令的一部分,解析器exit在开始执行之前读取main,因此可以保证main退出后不会读取进一步的源文件内容,即使某些未来的 bash 版本没有逐行处理输入首先。