如何編寫冪等的 Bash 指令碼?- Arslan

banq發表於2021-12-09

您編寫了一個 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 指令碼是您唯一需要的東西。

 

相關文章