從如何編寫冪等Bash指令碼瞭解怎麼實現冪等函式? · Fatih Arslan

banq發表於2019-07-08

當你你寫了一個bash指令碼,但是由於錯誤而執行一半退出了,當您修復了系統中的錯誤並再次執行這個指令碼。但是指令碼中的一半步驟會立即失敗,因為它們已經作用於您的系統了。要構建彈性系統,您需要編寫冪等的軟體。(冪等在分散式環境同樣重要,這樣才能保證重試等正確實現)

什麼是冪等?

冪等指令碼可以多次呼叫,每次呼叫它都會對系統產生相同的影響。這意味著,第二次呼叫將以相同的結果退出,並且不會產生任何副作用:

冪等:表示一個集合的元素,當它自身相乘或以其他方式操作時,其值不變。

良好的軟體總是以冪等方式編寫,特別是如果您在分散式系統中工作,其中操作可能最終是一致性的,並且由於重複請求(例如在具有交付保證的佇列中At-Least-Once),您最終可能會多次呼叫同一個函式。

Bash實現

讓我展示一些bash技巧,可以用來改變你的指令碼為冪等的。

1.建立一個空檔案

這意味著您可以多次呼叫它而不會出現任何問題。第二次呼叫不會對檔案內容產生任何影響。請注意,雖然它會更新檔案的修改時間,但如果您依賴它,請小心。

touch example.txt

2.建立目錄

切勿直接使用mkdir,而應將其與-p一起使用。如果目錄存在,此標誌確保mkdir不會出錯:

mkdir -p mydir

3. 建立符號連結

通常做法:

ln -s source target

但是如果你再次在同一個目標上呼叫它,會失敗。為了使其冪等,傳遞-f:

ln -sf source target

-f標誌在建立符號連結之前刪除目標符號,因此它將始終成功。

連結目錄時,您也需要傳遞-n。否則再次呼叫它將在目錄中建立一個符號連結。

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

所以為了安全起見,請始終使用ln -sfn source target。

4.刪除檔案

傳統:

rm example.txt

使用-f 忽略不存在的檔案的標誌。

rm -f example.txt

5.修改檔案

有時您正在向現有檔案新增新的一行。如果再次執行這個指令碼,則需要確保不要再次新增剛才新增的一行。假設你的指令碼這樣:

echo "/dev/sda1 /mnt/dev ext4 defaults 0 0" | sudo tee -a /etc/fstab

如果再次執行,您最終會有重複的條目/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語句。

(資料庫操作同理)

6.檢查變數,檔案或目錄是否存在

大多數情況下,您會寫入目錄,從檔案讀取或使用變數進行簡單的字串操作。例如,您可能有一個基於某些輸入建立新檔案的工具:

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:file並具有執行許可權

假設您要安裝二進位制檔案,但只有在主機中不存在二進位制檔案時,您才能使用-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並重新執行指令碼,即可輕鬆將二進位制檔案升級到新版本。

7.格式化裝置

要格式化卷,例如ext4格式化,一般使用如下命令:

mkfs.ext4 "$VOLUME_NAME"

如果再次呼叫它會立即失敗。為了使這個呼叫是冪等的,我們在它前面新增blkid:

blkid "$VOLUME_NAME" || mkfs.ext4 "$VOLUME_NAME"

此命令列印給定塊裝置的屬性。因此,預先基本上意味著僅在blkid失敗時繼續格式化,這表示給定的卷尚未格式化。

8.安裝裝置

嘗試將卷裝入現有目錄:

mount -o discard,defaults,noatime "$VOLUME_NAME" "$DATA_DIR"

如果它已經安裝,這將失敗。一種方法是檢查mount命令的輸出並檢視卷是否已經安裝。但是有一種更好的方法可以做到這一點。使用mountpoint命令:

if ! mountpoint -q "$DATA_DIR"; then
  mount -o discard,defaults,noatime "$VOLUME_NAME" "$DATA_DIR"
fi

總結

從長遠來看,建立冪等且有彈性的軟體總是有益的。因此,瞭解它們是有用的。最近我在bootstrap.sh 指令碼中使用了上述所有提示和技巧 ,用於建立和配置我的遠端開發機器。我知道我可以使用更復雜的工具從頭開始配置VM,但有時候你需要一個簡單的bash指令碼。

 

相關文章