如何编写幂等的 Bash 脚本?- Arslan


您编写了一个 bash 脚本,但由于错误而中途退出,您修复系统中的错误并再次运行脚本。但是脚本中的一半步骤会立即失败,因为它们已经应用于您的系统。要构建弹性系统,您需要编写幂等的软件。
 
什么是幂等性?
幂等脚本可以被多次调用,每次调用都会对系统产生相同的影响。这意味着,第二次调用将以相同的结果退出并且不会产生任何副作用:
幂等的:表示集合中的一个元素在与自身相乘或以其他方式操作时其值不变。
好的软件总是以幂等的方式编写的,尤其是当您在分布式系统中工作时,其中的操作可能最终是一致的,并且您可能会因重复请求(例如在具有At-Least-Once交付保证的队列中)而多次调用函数。
 
让我展示一些 bash 技巧和习惯用法,您可以使用它们将脚本更改为幂等的。您可能正在使用其中的大部分,而没有意识到副作用:
 
创建一个空文件
这是个简单的。默认情况下,touch是幂等的。这意味着您可以多次调用它而不会出现任何问题。第二次调用不会对文件内容产生任何影响。请注意,它会更新文件的修改时间,因此如果您依赖它,请小心。
touch example.txt
 
创建目录
切勿mkdir直接使用,而是与-p标志一起使用。如果目录存在,此标志确保 mkdir 不会出错:
mkdir -p mydir
 
创建符号链接
如果你在同一个目标上再次调用它,这将失败。要使其具有幂等性,请传递-f标志:
ln -sf source target
-f标志在创建符号链接之前删除目标目的地,因此它总是会成功。
链接目录时,您也需要传递-n。否则再次调用它会在目录中创建一个符号链接。

mkdir a
ln -sf a b
ln -sf a b
ls a
a

因此,为了安全起见,请始终使用ln -sfn source target.
 

删除文件
使用-f 忽略不存在文件的标志。
rm -f example.txt
 
修改文件
有时您会在现有文件中添加新行(即:)/etc/fstab。这意味着,如果您运行脚本,您需要确保不会第二次添加它。
幂等的一种方法是确保通过以下方式检查grep某些占位符:

if ! grep -qF "/mnt/dev" /etc/fstab; then
  echo
"/dev/sda1 /mnt/dev ext4 defaults 0 0" | sudo tee -a /etc/fstab
fi

这里的-q意思是静默模式和-F启用fixed string模式。如果/mnt/dev不存在,Grep 将无声地失败,因此永远不会调用 echo 语句。
 
检查变量、文件或目录是否存在
大多数情况下,您正在写入目录、读取文件或使用变量进行简单的字符串操作。
。例如,您可能有一个基于某些输入创建新文件的工具:
echo "complex set of rules" > /etc/conf/foo.txt
计算文本可能是一项昂贵的操作,因此您不想每次调用脚本时都编写它。为了使其具有幂等性,您可以通过shell的-f的内置test属性的标志检查文件是否存在:
if [ ! -f "/etc/conf/foo.txt" ]; then
 echo
"complex set of rules" > /etc/conf/foo.txt
fi

-f只是一个示例,您可以使用许多其他标志,例如:
  • -d: 目录
  • -z: 零长度的字符串
  • -p: 管道
  • -x: 文件并具有执行权限

假设你想安装一个二进制文件,但只有当它不存在于你的主机中时,你可以使用-x这样的:
# install 1password CLI
if ! [ -x "$(command -v op)" ]; then
  export OP_VERSION=
"v0.5.6-003"
  curl -sS -o 1password.zip https:
//cache.agilebits.com/dist/1P/op/pkg/${OP_VERSION}/op_linux_amd64_${OP_VERSION}.zip
  unzip 1password.zip op -d /usr/local/bin
  rm -f 1password.zip
fi

这会将op二进制文件安装到 /usr/local/bin。如果您重新运行脚本,它将不再安装它。另一个好处是,您只需将二进制文件从系统中删除,更新OP_VERSION env 并重新运行脚本,即可轻松将其升级到新版本。
有关完整标志和运算符的列表,请查看 man test。
 
我最近在bootstrap.sh 用于创建和配置远程开发机器的脚本中使用了上述所有提示和技巧 。我知道我可以使用更复杂的工具从头开始配置 VM,但有时一个简单的 bash 脚本是您唯一需要的东西。