教你寫出健壯可靠的shell腳本!

2021-02-24 Python愛好者社區

如果秉承著能跑就行的態度寫shell腳本,是很自在的,但是如果你想要寫出健壯,可靠的shell腳本,可沒那麼容易。那麼有什麼可操作的經驗或者方法嗎?

語法檢查

第一個最簡單的方法就是利用工具對腳本進行檢查,它能最大程度地發現shell腳本中存在的語法錯誤,如果你還不知道,建議你絕對不要錯過。

而為了保證腳本健壯可靠,那麼就需要保證腳本在一些特殊的情況及早出現,避免漏網之魚。來看看有哪些可行的技巧。

腳本失敗時即退出

可以在腳本的開頭設置如下:

set -e

舉個例子:

#!/bin/bash
set -e
lp    #這裡運行會出錯
date

這種情況下,運行一旦出錯就會退出,不放過一個問題:

$ ./test.sh
lp: Error - no default destination available.

當然了,這也有不好的地方,有時候命令執行本來就可能是失敗的,你還是希望它繼續,可以臨時加上|| true:

#!/bin/bash
set -e
lp  || true  
date

不過個人覺得這樣的設置用處不是特別大,因為很多時候就是需要處理不同的錯誤情況,而這樣只能要麼遇到錯誤退出,要麼認為正確,導致無法走到異常分支。
通過set +e設置回來:

set -e
#command
set +e
#other command

列印腳本執行過程

調試階段,你可能想知道整個過程是執行了哪些命令,每條命令都具體執行了什麼,可以利用下面的方式執行:

sh -x test.sh

或者,和上面類似,在開頭加上set -x:

//來源:公眾號【編程珠璣】
//作者:守望先生
#!/bin/bash
set -x
if [ $# -lt 1 ]
then
   echo  "no para"
else
   echo "para 1 $1"
fi

執行時,輸出如下:

+ [ 0 -le 1 ]
+ echo no para
no para

前面帶+的內容就是命令實際執行的,你可以看到比較條件是什麼,變量被展開成了具體內容,走到了哪個分支,非常清楚。

顯示未定義的變量

shell中變量沒有定義,仍然是可以使用的,但是它的結果可能不是你所預期的。舉個例子:

//來源:公眾號【編程珠璣】
//作者:守望先生#!/bin/bash
if [ "$var" = "abc" ]
then
   echo  " not abc"
else
   echo " abc "
fi

這裡本來想判斷var的內容是否為abc,實際上var並沒有定義,但是在這裡使用並沒有報錯,如果我們想早點發現這類問題,避免在複雜的腳本中問題被掩蓋,那麼可以在開頭加上:

set -u

再次運行就會提示:

test.sh: 5: test.sh: num: parameter not set

再想像一下,你本來想刪除:

rm -rf $dir/*

然後dir是空的時候,變成了什麼?

是不是有種後背發涼的感覺?

管道命令一個失敗時整個失敗

有時候我們可能會執行類似這樣的命令:

cat test.sh |grep if | cut -d ';' -f 2

三條命令一行執行,如果我們希望在其中一條失敗,整個命令就失敗,而避免執行後面無意義的命令,那麼可以在開始設置:

set -o pipefail

不設置的情況下,cat test.sh即使執行失敗了,後面的grep實際上還會繼續執行,可能會導致一些意想不到的情況發生,如果不想這樣的情況發生,那麼這樣設置是有幫助的。

對於靜態變量使用readonly

通常我們會在腳本開頭定義一些靜態變量:

MY_PATH=/usr/bin

而為了避免MY_PATH被意外修改,可以這樣:

readonly MY_PATH=/usr/bin

這樣的話,一旦後面有命令嘗試修改,就會報錯。

#!/bin/bash
readonly MY_PATH=/usr/bin
MY_PATH=/usr/local/bin

運行一下試試:

$ ./test.sh
test.sh: 3: test.sh: MY_PATH: is read only

看,給你提示了!

給變量設置可選的初始值

例如:

name=${1:-shouwang}
echo "${name}"

這裡讓name為$1,即第一個參數,而當它為空時,令name為shouwang。

多條命令執行使用&&

例如:

cmd0;cmd1;cmd1

這裡如果cmd0失敗了,後面的命令仍然會執行,而如果不希望後面的命令執行,可以使用:

cmd0 && cmd1 && cmd1

使用函數

腳本本身比較短還好,而腳本一旦變長,不使用函數,將使得腳本很難維護,可讀性也很差。

總結

實際上最開始介紹的腳本檢查工具就已經非常有效了,基本的錯誤都能檢查出來,而其他的內容,更多的是關注於腳本調試,不放過任何一個可能的錯誤。

最後,還是優先推薦shellcheck工具。

重磅!Python交流已成立

為了給小夥伴們提供一個互相交流的技術平臺,特地開通了Python交流群。群裡有不少技術大神,不時會分享一些技術要點,更有一些資源收藏愛好者不時分享一些優質的學習資料。(免費,不賣課!)

需要進群的朋友,可長按掃描下方二維碼。


▲長按掃碼

相關焦點

  • Shell 腳本編程最佳實踐
    前言由於工作需要,最近重新開始拾掇shell腳本。雖然絕大部分命令自己平時也經常使用,但是在寫成腳本的時候總覺得寫的很難看。而且當我在看其他人寫的腳本的時候,總覺得難以閱讀。畢竟shell腳本這個東西不算是正經的程式語言,他更像是一個工具,用來雜糅不同的程序供我們調用。
  • 編寫Linux Shell腳本的最佳實踐
    雖然絕大部分命令自己平時也經常使用,但是在寫成腳本的時候總覺得寫的很難看。而且當我在看其他人寫的腳本的時候,總覺得難以閱讀。畢竟shell腳本這個東西不算是正經的程式語言,他更像是一個工具,用來雜糅不同的程序供我們調用。因此很多人在寫的時候也是想到哪裡寫到哪裡,基本上都像是一段超長的main函數,不忍直視。
  • Shell 腳本編程最佳實踐
    前言由於工作需要,最近重新開始拾掇shell腳本。雖然絕大部分命令自己平時也經常使用,但是在寫成腳本的時候總覺得寫的很難看。而且當我在看其他人寫的腳本的時候,總覺得難以閱讀。畢竟shell腳本這個東西不算是正經的程式語言,他更像是一個工具,用來雜糅不同的程序供我們調用。
  • shell腳本的使用該熟練起來了,你說呢?(篇三)
    /hello_shell.sh 執行腳本,當前目錄下就會生成一個 lynfile 文件,裡面的內容為It is a test7.原樣輸出字符串,不進行轉義或取變量(用單引號)echo '$name\"'8.顯示命令執行結果echo `date
  • 運維必備:編寫 Bash Shell 腳本的最佳實踐
    雖然絕大部分命令自己平時也經常使用,但是在寫成腳本的時候總覺得寫的很難看。而且當我在看其他人寫的腳本的時候,總覺得難以閱讀。畢竟shell腳本這個東西不算是正經的程式語言,他更像是一個工具,用來雜糅不同的程序供我們調用。因此很多人在寫的時候也是想到哪裡寫到哪裡,基本上都像是一段超長的main函數,不忍直視。
  • shell腳本的使用該熟練起來了,你說呢?(篇二)
    本文轉載自【微信公眾號:羽林君,ID:Conscience_Remains】經微信公眾號授權轉載,如需轉載與原文作者聯繫shell傳遞參數shell傳遞參數我們可以在執行 Shell 腳本時,向腳本傳遞參數,腳本內獲取參數的格式為:$n。
  • 如何寫出安全的、基本功能完善的Bash腳本
    我本身也不是一個Bash腳本專家,但是我會在本文中跟你展示一個最基礎最簡單的安全腳本模板,會讓你寫的Bash腳本更加安全實用,你掌握了之後肯定會受益匪淺。Bash就像繼承了shell的衣缽一樣,在每臺linux上都可以看到他的身影,這可是大多數後端程序運行的環境,因此當你需要編寫伺服器的應用程式啟動、CI/CD步驟或集成測試用的腳本,Bash就在那裡等著你。將幾個命令粘在一起,將輸出從一個傳遞到另一個,然後只啟動一些可執行文件,Bash是眾多方案中最簡單的一個。
  • 分享:Charles 的腳本工具盒
    別名[1]》之後,一位讀者也向我們分享了他的工具盒,特此向大家推薦:Charles 的腳本[2]。他的腳本或許寫得不夠精妙,也許會存在一些 bug,但是正是這種對工作、生活中的積累進行整理,才是 Linux 生活的樂趣和進取之道。大家喜歡的話,也可以貢獻自己的代碼和貢獻,使之更加完善。以下內容引自他的項目說明[2]。你為什麼要安裝本項目?
  • linux實戰案例-讓你的shell編程更精進一步
    linux伺服器下的日常日誌處理功能01首先我們先創建幾個文件利用我們之前學的shell腳本批量創建幾個文件(這裡我們創建10個)第一步:touch createFileLog.sh第二步:vi createFileLog.sh 進入到shell腳本文件中進行編輯第三步:
  • ShellShock漏洞影響廣泛 企業如何防範?
    據悉,該漏洞與Bash處理來自作業系統或調用Bash腳本的應用程式的環境變量有關。如果Bash是默認的系統shell,網絡攻擊者可以通過發送Web請求、secure shell、telnet會話或其它使用Bash執行腳本的程序攻擊伺服器和其它Unix和Linux設備。  Bash除了可以將shell變量導出為環境變量,還可以將shell函數導出為環境變量。
  • shell編程訪問文件夾及alias永久生效的辦法
    有一些命令已經練習的比較熟練了,但是要經過三四串命令才能達到一個什麼目的,所以我想著學習一下shell編程來解決這個問題,這樣當我用alias(命令別名)的方式來調用程序的話,會極大地提高效率。需求1,我要先解決alias的問題,因為我一旦重新開一個shell就需要重新source,還是比較麻煩的。
  • 我的shellcode編寫之路 |MSF| Shellcode | kali linux 2017
    7.編譯、監聽、運行那麼我們得了到了msfvenom生成的shellcode,那麼我們將其帶入之前彈框的hellword代碼中,寫出以下代碼:8.Bash下的編寫思路形成懶人自動化的腳本我們要考慮幾點內容:如何將我們生成的shellcode代碼代入到cpp當中如何指定ip和埠 自動化的幫我們完成所有事情
  • dos2unix批量轉換腳本
    這個腳本是解決使用 Windows結尾格式的文本文件在 Linux下面使用的時候會出現莫名其妙錯誤的問題,一般我們使用 Linux下面的 dos2unix命令轉換文件的格式即可,但是如果我們需要批量轉換的話,這就有點麻煩了,可以使用腳本來進行處理。
  • shell常用命令
    - find指令後面必須有基本路徑,-path後面的目錄前後都要加* - shell中命令之間的空格很重要,空格分隔了不同的命令,\轉義的一般都用空格與其他的指令隔離 - shell常用變量:\\$1命令或腳本的第一個參數,第二個以此類推;\$#參數數量;$0當前程序名稱;$?
  • 甲大人:教你8招寫出寫出最佳電商店鋪文案
    甲大人:教你8招寫出寫出最佳電商店鋪第一大要素就是分析產品,只有對產品足夠的了解,進行全方位的分析,才能夠寫出最符合產品同時也最出彩的文案。甲大人:教你8招寫出寫出最佳電商店鋪對用戶足夠的了解也是寫出好文案的關鍵因素。
  • WinCC上基本的VB腳本和C腳本調試工具
    pwnameSet objCircle= ScreenItems("圓1" )objCircle.Radius = 60Set screenname=HMIRuntime.Screens("Home1") //獲取要操作的窗體Set pwname=screenname.ScreenItems("畫面窗口2") //獲取要操作的控制項,這裡填入你要操作的控制項名
  • 蘋果要求Linux和Unix Shell的開發者從App Store下架應用,但最後...
    近期蘋果以看似反轉的姿態,對Linux和Unix shell-app的開發者進行了打擊,聲稱他們違反了App Store審核准則。Linux和Unix shell本質上是命令行界面,在這種情況下,安裝在通常不具備命令行功能的設備上。iSH和Blink Shell等應用提供了這些工具,為有權限的用戶或IT開發者提供更多的功能。
  • 老外告訴我shell out意思是付帳,shell貝殼怎麼會和付款扯上關係
    Shell out的意思是為…花費一大筆錢,它的英文釋義為If you shell out for something, you spend a lot of money on it.例如:I had to shell out a lot of money for my new car
  • Spawning A TTY Shell-逃逸 Linux 各種 Shell 來執行命令
    bash:set shell=/bin/bash:shellFrom within nmap!>find:find / -name test -exec /bin/sh or /bin/bash \;ssh:ssh username@IP – t "/bin/sh" or "/bin/bash"ssh username@IP -t "bash –noprofile"ssh username@IP -t "() { :; }; /bin/bash" (shellshock
  • 野隊「腳本」橫行的原因是什麼?誰最想封禁腳本?
    所以,遊戲中所有的收益無論是全局還是銀幣,甚至可以使金幣(畢竟你賺RMB要花時間去工作),都可以換算成一定量的時間。簡單來說,刨掉中間收益系統對你時間價值的換算(技術好單位時間內換到的收益就高,高帳、金幣車以及各種加成本質上都是花錢來提高時間價值的手段),這個遊戲本質上其實是用時間去換坦克。