溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

寫shell腳本需要注意哪些事項

發(fā)布時間:2022-02-17 15:31:26 來源:億速云 閱讀:211 作者:iii 欄目:開發(fā)技術

今天小編給大家分享一下寫shell腳本需要注意哪些事項的相關知識點,內(nèi)容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

寫shell腳本需要注意哪些事項

1. 指定bash

shell 腳本的第一行,#!之后應該是什么?如果拿這個問題去問別人,不同的人的回答可能各不相同。 我見過/usr/bin/env bash,也見過/bin/bash,還有/usr/bin/bash,還有/bin/sh,還有/usr/bin/env sh。這算是編程界的“’茴’字四種寫法”了。 在多數(shù)情況下,以上五種寫法都是等價的。但是,寫過程序的人都知道:“少數(shù)情況”里往往隱藏著意想不到的坑。

如果系統(tǒng)的默認 shell 不是 bash 怎么辦?比如某 Linux 發(fā)行版的某個版本,默認的 sh 就不是 bash。 如果系統(tǒng)的 bash 不是在 /usr/bin/bash怎么辦?

我推薦使用 /usr/bin/env bash和 /bin/bash。前者通過env添加一個中間層,讓env在$PATH中搜索bash;后者則是官方背書的,約定俗成的 bash 位置,/usr/bin/bash不過是指向它的一個符號鏈接。

2. set -e 和 set -x

OK,經(jīng)過一番討論,現(xiàn)在第一行定下來了。接下來該開始寫第二行了吧? 且慢!在你開始構思并寫下具體的代碼邏輯之前,先插入一行set -e和一行set -x。 set -x會在執(zhí)行每一行 shell 腳本時,把執(zhí)行的內(nèi)容輸出來。它可以讓你看到當前執(zhí)行的情況,里面涉及的變量也會被替換成實際的值。 set -e會在執(zhí)行出錯時結束程序,就像其他語言中的“拋出異?!币粯印#蚀_說,不是所有出錯的時候都會結束程序,見下面的注) 注:set -e結束程序的條件比較復雜,在man bash里面,足足用了一段話描述各種情景。大多數(shù)執(zhí)行都會在出錯時退出,除非 shell 命令位于以下情況:

  1. 一個 pipeline 的非結尾部分,比如error | ok
  2. 一個組合語句的非結尾部分,比如ok && error || other
  3. 一連串語句的非結尾部分,比如error; ok
  4. 位于判斷語句內(nèi),包括test、if、while等等。

這兩個組合在一起用,可以在 debug 的時候替你節(jié)省許多時間。出于防御性編程的考慮,有必要在寫第一行具體的代碼之前就插入它們。捫心自問,寫代碼的時候能夠一次寫對的次數(shù)有多少?大多數(shù)代碼,在提交之前,通常都經(jīng)歷過反復調(diào)試修改的過程。與其在焦頭爛額之際才引入這兩個配置,不如一開始就給 debug 留下余地。在代碼終于可以提交之后,再考慮是否保留它們也不遲。

3. 帶上shellcheck

好了,現(xiàn)在我已經(jīng)有了三行(樣板)代碼,具體的業(yè)務邏輯一行都沒寫呢。是不是該開始寫了? 且慢!工欲善其事,必先利其器。這次,我就介紹一個 shell 腳本編寫神器:shellcheck

說來慚愧,雖然寫了幾年 shell 腳本,有些語法我還是記不清楚。這時候就要依仗 shellcheck 指點一下了。 shellcheck 除了可以提醒語法問題以外,還能檢查出 shell 腳本編寫常見的 bad code。本來我的N條建議里面,還有幾條是關于這些 bad code 的,不過考慮到 shellcheck 完全可以發(fā)掘出這些問題,于是忍痛把它們都剔除在外了。毫無疑問,使用 shellcheck 給我的 shell 編寫技能帶來了巨大的飛躍。

所謂“站在巨人的肩膀上”,雖然我們這些新兵蛋子,技能不如老兵們強,但是我們可以在裝備上趕上對方啊!動動手安裝一下,就能結識一個循循善誘的“老師”,何樂而不為?順便一提,shellcheck 居然是用 haskell 寫的。誰說 haskell 只能用來裝逼?

4. 變量展開

在 shell 腳本中,偶爾可以看到這樣的做法:

echo $xxx | awk/sed/grep/cut...

看起來大張形勢的樣子,其實不過是想修改一個變量的值。殺雞何必用牛刀?bash內(nèi)建的變量展開機制已經(jīng)足以滿足你各種需求!還是老方法, read the f**k manaul! man bash然后搜索Parameter Expansion,下面就是你想要的技巧。鍵者也寫過一篇相關的文章,希望能助上一臂之力:玩轉(zhuǎn)Bash變量

5. 注意local

隨著代碼越寫越多,你開始把重復的邏輯提煉成函數(shù)。有可能你會掉到bash的一個坑里。在bash,如果不加 local 限定詞,變量默認都是全局的。變量默認全局——這跟 js 和 lua 相似;但相較而言,很少有 bash 教程一開始就告知你這個事實。在頂級作用域里,是否是全局變量并不重要。但是在函數(shù)里面,聲明一個全局變量可能會污染到其他作用域(尤其在你根本沒有注意到這一點的情況下)。所以,對于在函數(shù)內(nèi)聲明的變量,請務必記得加上 local 限定詞。

6. trap信號

如果你寫過稍微復雜點的在后臺運行的程序,應該知道 posix 標準里面“信號”是什么一回事。如果不知道,直接看下一段。像其他語言一樣,shell 也支持處理信號。trap sighandler INT可以在接收到 SIGINT 時調(diào)用 sighandler 函數(shù)。捕獲其他信號的方式以此類推。

不過 trap 的主要應用場景可不是捕獲哪個信號。trap命令支持“捕獲”許多不同的流程——準確來說,允許用戶給特定的流程注入函數(shù)調(diào)用。其中最為常用的是trap func EXIT和trap func ERR。 trap func EXIT允許在腳本結束時調(diào)用函數(shù)。由于無論正常退出抑或異常退出,所注冊的函數(shù)都能得以調(diào)用,在需要調(diào)用一個清理函數(shù)的場景下,我都是用它注冊清理函數(shù),而不是簡單地在腳本結尾調(diào)用清理函數(shù)。 trap func ERR允許在運行出錯時調(diào)用函數(shù)。一個常用的技法是,使用全局變量ERROR存儲錯誤信息,然后在注冊的函數(shù)中根據(jù)存儲的值完成對應的錯誤報告。把原本四分五裂的錯誤處理邏輯集中到一處,有時候會起奇效。不過要記住,程序異常退出時,既會調(diào)用EXIT注冊的函數(shù),也會調(diào)用ERR注冊的函數(shù)。

7. 三思后行

以上幾條都是具體的建議,剩下兩條比較務虛。

這條建議的名字叫“三思而行”。其實無論寫什么代碼,哪怕只是一個輔助腳本,都要三思而行,切忌粗心大意。不,寫腳本的時候更要記住這點。畢竟許多時候,一個復雜的腳本發(fā)端于幾行小小的命令。一開始寫這個腳本的人,也許以為它只是一次性任務。代碼里難免對一些外部條件有些假定,在當時也許是正常的,但是隨著外部環(huán)境的變化,這些就成了隱藏的暗礁。雪上加霜的是,幾乎沒有人會給腳本做測試。除非你去運行它,否則不知道它是否還能正常使用。

要想減緩腳本代碼的腐爛速度,需要在編寫的時候辨清哪些是會變的依賴、哪些是腳本正常運行所不可或缺的。要有適當?shù)某橄?,編寫可變更的代碼;同時要有防御性編程的意識,給自己的代碼一道護城河。

8. 揚長避短

有些時候,使用 shell 寫腳本就意味著難以移植、難以統(tǒng)一地進行錯誤處理、難以利索地處理數(shù)據(jù)。 雖然使用外部的命令可以方便快捷地實現(xiàn)各種復雜的功能,但作為硬幣的反面,不得不依靠grep、sed、awk等各種工具把它們粘合在一起。 如果有兼容多平臺的需求,還得小心規(guī)避諸如BSD和GNU coreutils,bash版本差異之類奇奇怪怪的陷阱。 由于缺乏完善的數(shù)據(jù)結構以及一致的API,shell 腳本在處理復雜的邏輯上力不從心。 解決特定的問題要用合適的工具。知道什么時候用 shell,什么時候切換到另外一門更通用的腳本語言(比如ruby/python/perl),這也是編寫可靠 shell 腳本的訣竅。如果你的任務可以組合常見的命令來完成,而且只涉及簡單的數(shù)據(jù),那么 shell 腳本就是適合的錘子。如果你的任務包含較為復雜的邏輯,而且數(shù)據(jù)結構復雜,那么你需要用ruby/python之類的語言編寫腳本。

以上就是“寫shell腳本需要注意哪些事項”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI