Bash指令碼15分鐘進階教程

發表於2014-04-22

這裡的技術技巧最初是來自谷歌的“Testing on the Toilet” (TOTT)。這裡是一個修訂和擴增版本。

指令碼安全

我的所有bash指令碼都以下面幾句為開場白:

這樣做會避免兩種常見的問題:

  1. 引用未定義的變數(預設值為“”)
  2. 執行失敗的命令被忽略

需要注意的是,有些Linux命令的某些引數可以強制忽略發生的錯誤,例如“mkdir -p” 和 “rm -f”。

還要注意的是,在“errexit”模式下,雖然能有效的捕捉錯誤,但並不能捕捉全部失敗的命令,在某些情況下,一些失敗的命令是無法檢測到的。(更多細節請參考這個帖子。)

指令碼函式

在bash裡你可以定義函式,它們就跟其它命令一樣,可以隨意的使用;它們能讓你的指令碼更具可讀性:

還有一些例子:

儘可能的把你的bash程式碼移入到函式裡,僅把全域性變數、常量和對“main”呼叫的語句放在最外層。

變數註解

Bash裡可以對變數進行有限的註解。最重要的兩個註解是:

  1. local(函式內部變數)
  2. readonly(只讀變數)

這樣,你可以將一個以前不是隻讀變數的變數宣告成只讀變數:

儘量對你bash指令碼里的所有變數使用localreadonly進行註解。

$()代替反單引號(`)

反單引號很難看,在有些字型裡跟正單引號很相似。$()能夠內嵌使用,而且避免了轉義符的麻煩。

[[]](雙層中括號)替代[]

使用[[]]能避免像異常的副檔名之類的問題,而且能帶來很多語法上的改進,而且還增加了很多新功能:

操作符 功能說明
|| 邏輯or(僅雙中括號裡使用)
&& 邏輯and(僅雙中括號裡使用)
< 字串比較(雙中括號裡不需要轉移)
-lt 數字比較
= 字串相等
== 以Globbing方式進行字串比較(僅雙中括號裡使用,參考下文)
=~ 用正規表示式進行字串比較(僅雙中括號裡使用,參考下文)
-n 非空字串
-z 空字串
-eq 數字相等
-ne 數字不等

單中括號:

雙中括號

正規表示式/Globbing

使用雙中括號帶來的好處用下面幾個例子最能表現:

注意,從bash 3.2版開始,正規表示式和globbing表示式都不能用引號包裹。如果你的表示式裡有空格,你可以把它儲存到一個變數裡:

按Globbing方式的字串比較也可以用到case語句中:

字串操作

Bash裡有各種各樣操作字串的方式,很多都是不可取的。

基本使用者

替換操作(使用globbing)

刪除頭部或尾部(使用globbing)

避免使用臨時檔案

有些命令需要以檔名為引數,這樣一來就不能使用管道。這個時候?<()?就顯出用處了,它可以接受一個命令,並把它轉換成可以當成檔名之類的什麼東西:

還有一個非常有用處的是”here documents”,它能讓你在標準輸入上輸入多行字串。下面的’MARKER’可以替換成任何字詞。

如果文字里沒有內嵌變數替換操作,你可以把第一個MARKER用單引號包起來:

內建變數

變數 說明
$0 指令碼名稱
$n 傳給指令碼/函式的第n個引數
$$ 指令碼的PID
$! 上一個被執行的命令的PID(後臺執行的程式)
$? 上一個命令的退出狀態(管道命令使用${PIPESTATUS})
$# 傳遞給指令碼/函式的引數個數
$@ 傳遞給指令碼/函式的所有引數(識別每個引數)
$* 傳遞給指令碼/函式的所有引數(把所有引數當成一個字串)
提示
使用$*很少是正確的選擇。
$@能夠處理空格引數,而且引數間的空格也能正確的處理。
使用$@時應該用雙引號括起來,像”$@”這樣。

除錯

對指令碼進行語法檢查:

跟蹤指令碼里每個命令的執行:

跟蹤指令碼里每個命令的執行並附加擴充資訊:

你可以在指令碼頭部使用set -o verboseset -o xtrace來永久指定-v-o。當在遠端機器上執行指令碼時,這樣做非常有用,用它來輸出遠端資訊。

什麼時候不應該使用bash指令碼

  • 你的指令碼太長,多達幾百行
  • 你需要比陣列更復雜的資料結構
  • 出現了複雜的轉義問題
  • 有太多的字串操作
  • 不太需要呼叫其它程式和跟其它程式管道互動
  • 擔心效能

這個時候,你應該考慮一種指令碼語言,比如Python或Ruby。

參考

相關文章