在bash中,我正在构建更新脚本,如何更新更新程序脚本

时间:2019-01-09 00:25:51

标签: bash shell auto-update

我正在构建一个小脚本来更新树莓派上的应用程序文件。

它将执行以下操作:

  1. 下载应用程序文件的zip文件
  2. 解压缩它们
  3. 将每个副本复制到正确的位置,并根据需要使其可执行等。

我遇到的问题是其中一个文件是updatescript.sh。

我已经读到,在执行过程中更新/更改bash脚本很危险。参见Edit shell script while it's running

有没有一种好的方法可以实现我想要做的事情?

2 个答案:

答案 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
  1. 检查您是否从临时目录运行
  2. 如果不是,请复制自己,然后从临时目录中重新运行

您甚至可以使用环境变量或参数传递一些变量/状态。然后,您可以使用简单的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锁定。