編寫可靠bash腳本的一些技巧

編寫可靠bash腳本的一些技巧

原作者:騰訊技術工程

原文鏈接:https://zhuanlan.zhihu.com/p/123989641

寫過很多 bash 腳本的人都知道,bash 的坑不是一般的多。 其實 bash 本身并不是一個很嚴謹的語言,但是很多時候也不得不用。以下總結了一些鵝廠程序員在編寫可靠 bash 腳本的一些小 tips。

0. set -x -e -u -o pipefail

在寫腳本時,在一開始(Shebang 之后)就加上這一句,或者它的縮略版:

set -xeuo pipefail

這能避免很多問題,更重要的是能讓很多隱藏的問題暴露出來。

下面說明每個參數的作用,以及一些例外的處理方式 :

-x : 在執行每一個命令之前把經過變量展開之后的命令打印出來。

這個對于 debug 腳本、輸出 Log 時非常有用。 正式運行的腳本也可以不加。

-e : 遇到一個命令失敗(返回碼非零)時,立即退出。

bash 跟其它的腳本語言最大的不同點之一,應該就是遇到異常時繼續運行下一條命令。 這在很多時候會遇到意想不到的問題。加上 -e ,會讓 bash 在遇到一個命令失敗時,立即退出。

如果有時確實需要忽略個別命令的返回碼,可以用 || true 。如:

some_cmd || true        # 即使some_cmd失敗了,仍然會繼續運行
some_cmd || RET=$?      # 或者可以這樣來收集some_cmd的返回碼,供后面的邏輯判斷使用

但是在管道串起多條命令的情況下,只有最后一條命令失敗時才會退出。如果想讓管道中任意一條命令失敗就退出,就要用后面提到的-o pipefail 了。

加-e 有時候可能會不太方便,動不動就退出。但覺得還是應該堅持所謂的fail-fast 原則,也就是有異常時停止正常運行,而不是繼續嘗試運行可能存在缺陷的過程。如果有命令可以明確忽略異常,那可以用上面提到的 || true 等方式明確地忽略之。

-u :試圖使用未定義的變量,就立即退出。

如果在 bash 里使用一個未定義的變量,默認是會展開成一個空串。有時這種行為會導致問題,比如:

rm -rf $MYDIR/data

如果 MYDIR 變量因為某種原因沒有賦值,這條命令就會變成 rm -rf /data 。 這就比較搞笑了。。 使用 -u 可以避免這種情況。

但有時候在已經設置了-u 后,某些地方還是希望能把未定義變量展開為空串,可以這樣寫:

${SOME_VAR:-}#  bash變量展開語法,可以參考:
https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

-o pipefail : 只要管道中的一個子命令失敗,整個管道命令就失敗。

pipefail 與-e 結合使用的話,就可以做到管道中的一個子命令失敗,就退出腳本。

1. 防止重疊運行

在一些場景中,我們通常不希望一個腳本有多個實例在同時運行。比如用 crontab 周期性運行腳本時,有時不希望上一個輪次還沒運行完,下一個輪次就開始運行了。 這時可以用 flock 命令來解決。 flock 通過文件鎖的方式來保證獨占運行,并且還有一個好處是進程退出時,文件鎖也會自動釋放,不需要額外處理。

用法 1: 假設你的入口腳本是 myscript.sh,可以新建一個腳本,通過 flock 來運行它:

# flock --wait 超時時間   -e 鎖文件   -c "要執行的命令"
# 例如:
flock  --wait 5  -e "lock_myscript"  -c "bash myscript.sh"

用法 2: 也可以在原有腳本里使用 flock。 可以把文件打開為一個文件描述符,然后使用 flock 對它上鎖(flock 可以接受文件描述符參數)。

exec 123<>lock_myscript   # 把lock_myscript打開為文件描述符123
flock  --wait 5  123 || { echo 'cannot get lock, exit'; exit 1; }

2. 意外退出時殺掉所有子進程

我們的腳本通常會啟動好多子腳本和子進程,當父腳本意外退出時,子進程其實并不會退出,而是繼續運行著。 如果腳本是周期性運行的,有可能發生一些意想不到的問題。

在 stackoverflow 上找到的一個方法,原理就是利用 trap 命令在腳本退出時 kill 掉它整個進程組。 把下面的代碼加在腳本開頭區,實測管用:

trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

不過如果父進程是用 SIGKILL (kill -9) 殺掉的,就不行了。因為 SIGKILL 時,進程是沒有機會運行任何代碼的。

3. timeout 限制運行時間

有時候需要對命令設置一個超時時間。這時可以使用 timeout 命令,用法很簡單:

timeout 600s  some_command arg1 arg2

命令在超時時間內運行結束時,返回碼為 0,否則會返回一個非零返回碼。

timeout 在超時時默認會發送 TERM 信號,也可以用 -s 參數讓它發送其它信號。

4. 連續管道時,考慮使用 tee 將中間結果落盤,以便查問題

有時候我們會用到把好多條命令用管道串在一起的情況。如 cmd1 | cmd2 | cmd3 | …這樣會讓問題變得難以排查,因為中間數據我們都看不到。

如果改成這樣的格式:

cmd1 > out1.dat
cat out1 | cmd2 > out2.dat
cat out2 | cmd3 > out3.dat

性能又不太好,因為這樣 cmd1, cmd2, cmd3 是串行運行的,這時可以用 tee 命令:

cmd1 | tee out1.dat | cmd2 | tee out2.dat | cmd3 > out3.dat

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/532561.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532561.shtml
英文地址,請注明出處:http://en.pswp.cn/news/532561.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python 到 poc

0x01 特殊函數 0x02 模塊 0x03 小工具開發記錄 特殊函數 # -*- coding:utf-8 -*- #內容見POC.demo; POC.demo2 ;def add(x,y):axyprint(a)add(3,5) print(------------引入lambad版本&#xff1a;) add lambda x,y : xy print(add(3,5)) #lambda函數,在lambda函數后面直接…

protobuf版本常見問題

protobuf版本常見問題 許多軟件都依賴 google 的 protobuf&#xff0c;我們很有可能在安裝多個軟件時重復安裝了多個版本的 protobuf&#xff0c;它們之間很可能出現沖突并導致在后續的工作中出現版本不匹配之類的錯誤。本文將討論筆者在使用 protobuf 中遇到的一些問題&#…

CMake常用命令整理

CMake常用命令整理 轉自&#xff1a;https://zhuanlan.zhihu.com/p/315768216 CMake 是什么我就不用再多說什么了&#xff0c;相信大家都有接觸才會看一篇文章。對于不太熟悉的開發人員可以把這篇文章當個查找手冊。 1.CMake語法 1.1 指定cmake的最小版本 cmake_minimum_r…

CVE-2021-41773 CVE-2021-42013 Apache HTTPd最新RCE漏洞復現 目錄穿越漏洞

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; CVE-2021-41773漏洞描述&#xff1a; Apache HTTPd是Apache基金會開源的一款流行的HTTP服務器。2021年10月8日Apache HTTPd官方發布安全更新&#xff0c;披…

SSRF,以weblogic為案例

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 復習一下ssrf的原理及危害&#xff0c;并且以weblog的ssrf漏洞為案例 漏洞原理 SSRF(Server-side Request Forge, 服務端請求偽造) 通常用于控制web進而…

C++11 右值引用、移動語義、完美轉發、萬能引用

C11 右值引用、移動語義、完美轉發、引用折疊、萬能引用 轉自&#xff1a;http://c.biancheng.net/ C中的左值和右值 右值引用可以從字面意思上理解&#xff0c;指的是以引用傳遞&#xff08;而非值傳遞&#xff09;的方式使用 C 右值。關于 C 引用&#xff0c;已經在《C引用…

C++11 std::function, std::bind, std::ref, std::cref

C11 std::function, std::bind, std::ref, std::cref 轉自&#xff1a;http://www.jellythink.com/ std::function 看看這段代碼 先來看看下面這兩行代碼&#xff1a; std::function<void(EventKeyboard::KeyCode, Event*)> onKeyPressed; std::function<void(Ev…

Java安全(一) : java類 | 反射

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1.java基礎 Java平臺共分為三個主要版本Java SE&#xff08;Java Platform, Standard Edition&#xff0c;Java平臺標準版&#xff09;、Java EE&#xff0…

LeetCode-287 尋找重復數 二分法

LeetCode-287 尋找重復數 二分法 287. 尋找重復數 給定一個包含 n 1 個整數的數組 nums &#xff0c;其數字都在 1 到 n 之間&#xff08;包括 1 和 n&#xff09;&#xff0c;可知至少存在一個重復的整數。 假設 nums 只有 一個重復的整數 &#xff0c;找出 這個重復的數 。…

對某公司一次弱口令到存儲型xss挖掘

轉自我的奇安信攻防社區文章:https://forum.butian.net/share/885 免責聲明: 滲透過程為授權測試,所有漏洞均以提交相關平臺,博客目的只為分享挖掘思路和知識傳播** 涉及知識: xss注入及xss注入繞過 挖掘過程: 某次針對某目標信息搜集無意發現某工程公司的項目招標平臺 …

C++11新特性選講 語言部分 侯捷

C11新特性選講 語言部分 侯捷 本課程分為兩個部分&#xff1a;語言的部分和標準庫的部分。只談新特性&#xff0c;并且是選講。 本文為語言部分筆記。 語言 Variadic Templatesmove semanticsautoRange-based for loopInitializer listLambdas… 標準庫 type_traitsunodered…

java安全(二):JDBC|sql注入|預編譯

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1 JDBC基礎 JDBC(Java Database Connectivity)是Java提供對數據庫進行連接、操作的標準API。Java自身并不會去實現對數據庫的連接、查詢、更新等操作而是通…

java安全(三)RMI

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1.RMI 是什么 RMI(Remote Method Invocation)即Java遠程方法調用&#xff0c;RMI用于構建分布式應用程序&#xff0c;RMI實現了Java程序之間跨JVM的遠程通信…

LeetCode-726 原子的數量 遞歸

LeetCode-726 原子的數量 遞歸 題目鏈接&#xff1a;LeetCode-726 原子的數量 給你一個字符串化學式 formula &#xff0c;返回 每種原子的數量 。 原子總是以一個大寫字母開始&#xff0c;接著跟隨 0 個或任意個小寫字母&#xff0c;表示原子的名字。 如果數量大于 1&#xf…

java安全(四) JNDI

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1.JNDI JNDI(Java Naming and Directory Interface)是Java提供的Java 命名和目錄接口。通過調用JNDI的API應用程序可以定位資源和其他程序對象。JNDI是Java…

二叉樹的層序遍歷和前中后序遍歷代碼 迭代/遞歸

前中后序遍歷&#xff08;DFS&#xff09; 首先我們要明確前中后序遍歷的順序&#xff1a; 前序&#xff1a;中左右中序&#xff1a;左中右后序&#xff1a;左右中 前中后序遍歷的遞歸代碼和迭代代碼分別有各自的框架&#xff0c;然后根據遍歷順序調整記錄元素的位置即可。 …

java安全(五)java反序列化

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 1. 序列化 在調用RMI時,發現接收發送數據都是反序列化數據. 例如JSON和XML等語言,在網絡上傳遞信息,都會用到一些格式化數據,大多數處理方法中&#xff0c…

git merge和rebase的區別與選擇

git merge和rebase的區別與選擇 轉自&#xff1a;https://github.com/geeeeeeeeek/git-recipes/wiki/5.1-%E4%BB%A3%E7%A0%81%E5%90%88%E5%B9%B6%EF%BC%9AMerge%E3%80%81Rebase-%E7%9A%84%E9%80%89%E6%8B%A9#merge BY 童仲毅&#xff08;geeeeeeeeekgithub&#xff09; 這是一篇…

java安全(六)java反序列化2,ysoserial調試

給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; 給個關注&#xff1f;寶兒&#xff01; ysoserial 下載地址&#xff1a;https://github.com/angelwhu/ysoserial ysoserial可以讓?戶根據??選擇的利?鏈&#xff0c;?成反序列化利?數據&…

C++面試常見問題一

C面試常見問題一 轉自&#xff1a;https://oldpan.me/archives/c-interview-answer-1 原作者&#xff1a;[oldpan][https://oldpan.me/] 前言 這里收集市面上所有的關于算法和開發崗最容易遇到的關于C方面的問題&#xff0c;問題信息來自互聯網以及牛客網的C面試題目匯總。答題…