我正在构建一个小脚本来更新树莓派上的应用程序文件。
它将执行以下操作:
我遇到的问题是其中一个文件是updatescript.sh。
我已经读到,在执行过程中更新/更改bash脚本很危险。参见Edit shell script while it's running
有没有一种好的方法可以实现我想要做的事情?
答案 0 :(得分:2)
您阅读的内容被严重夸大了。
通过mv
在其上覆盖另一个文件来完全覆盖外壳脚本是完全安全的。执行此操作时,旧文件句柄仍然有效,请参阅未经修改的原始文件内容。您不能安全地做的是就地编辑现有文件。
因此,以下方法很好(这也是您所有操作系统供应商更新工具(如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
...这很危险:
curl https://example.com/whatever >/usr/local/bin/whatever
第一个(而不是第二个)操作是这样的:下载脚本的新版本时,请将其写入另一个文件,并在下载成功后才将其重命名为原始文件。这就是您要确保原子性的全部操作。
(上面还进行了一些代码签名验证实践的演示,因为,在构建更新程序时,您需要使用它们。您不会在不验证签名的情况下尝试通过自动下载来分发代码,对吧。 ?因为这是对Web服务器的简单侵入,导致您的每个客户都拥有0所有权,因此上述方法希望您的代码签名密钥的公共端位于~/.gnupg/trustedkeys.gpg
中,但您可以将{{1 }},并使用环境变量trustedkeys.gpg
指向它。
即使您不能安全地编写更新代码,也要减轻这种风险。如果将脚本的主体移到一个函数中,则必须完全读取它在文件的任何部分可以执行之前,没有文件在执行开始时就没有被读取。
GNUPGHOME
由于#!/usr/bin/env bash
main() {
echo "Logic all goes here"
}; { main; exit; }
是复合命令的一部分,因此解析器在开始执行{ main; exit; }
之前先读取exit
,因此可以确保以后不会再读取任何源文件内容main
退出,即使某些将来的bash版本最初并未逐行处理输入。
答案 1 :(得分:1)
基本上可以做一些事情:
shouldbe="/tmp/$(basename "$0")"
if [ "$0" != "$shouldbe" ]; then
cp "$0" "$shouldbe"
exec env REALPATH="$0" "$shouldbe" "$@"
fi
您甚至可以使用环境变量或参数传递一些变量/状态。然后,您可以使用简单的cp
来更新自己,因为不再有旧路径的来源(甚至没有打开过)。
cp "new_script_version.sh" "$REALPATH"
脚本看起来像这样:
#!/bin/bash
# we need to be run from /tmp directory
shouldbe="/tmp/$(basename "$0")"
if [ "$0" != "$shouldbe" ]; then
cp "$0" "$shouldbe"
exec env REALPATH="$0" "$shouldbe" "$@"
fi
echo "Updatting...."
echo "downloading zip files"
echo "unziping zip files..."
echo "Copying each zip files etc."
cp directory"new_updatescript.sh "$REALPATH"
echo "Update succedded"
可通过tutorialspoint获得实时/测试版本。
为了以防万一,还可以对脚本实施flock
锁定。