如何編寫冪等的Bash指令碼(函式)? · Fatih Arslan
當你你寫了一個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指令碼。
相關文章
- 從如何編寫冪等Bash指令碼瞭解怎麼實現冪等函式? · Fatih Arslan指令碼函式
- 如何編寫冪等的 Bash 指令碼?- Arslan指令碼
- 解析如何在Bash中編寫函式函式
- Linux編寫Bash指令碼的10個技巧Linux指令碼
- 編寫更好 Bash 指令碼的 8 個建議指令碼
- 如何編寫高效的 Shell 指令碼指令碼
- 寫出健壯的Bash指令碼指令碼
- 如何更好的編寫async函式函式
- 如何編寫翻頁函式?函式
- 提高程式碼質量:如何編寫函式函式
- QTP指令碼編寫技巧 - 從函式中返回多個值的方法QT指令碼函式
- 如何寫出安全的、基本功能完善的Bash指令碼指令碼
- 如何使用zx編寫shell指令碼指令碼
- shell 指令碼如何編寫-致初學者指令碼
- 使用Lua編寫可嵌入式指令碼指令碼
- Bash指令碼指令碼
- 如何編寫高質量的函式 -- 敲山震虎篇函式
- Bash函式函式
- gdb指令碼編寫指令碼
- Shell 指令碼編寫指令碼
- 乾淨的程式碼: 編寫可讀的函式函式
- js冪函式程式碼例項分享JS函式
- 編譯FFMPEG原始碼的指令碼編寫案例編譯原始碼指令碼
- 如何用 JMeter 編寫效能測試指令碼?JMeter指令碼
- 如何編寫測試團隊通用的Jmeter指令碼JMeter指令碼
- TOM大神編寫的show_space函式程式碼函式
- 感悟篇:如何寫好函式式程式碼函式
- 油猴指令碼編寫指令碼
- 編寫git指令碼.shGit指令碼
- [20210107]編寫bash shell指令碼遇到的問題.txt指令碼
- js編寫trim()函式JS函式
- 編寫shell指令碼的規範指令碼
- jQuery函式的等價原生函式程式碼示例jQuery函式
- 函式的冪級數展開式函式
- 分散式之介面冪等性分散式
- [java]如何裂解RESTful的冪等性JavaREST
- 如何編寫高質量的 JS 函式(1) -- 敲山震虎篇JS函式
- 【Java面試】什麼是冪等?如何解決冪等性問題?Java面試