這里的技術(shù)技巧最初是來(lái)自谷歌的“Testing on the Toilet” (TOTT)。這里是一個(gè)修訂和擴(kuò)增版本。
腳本安全
我的所有bash腳本都以下面幾句為開(kāi)場(chǎng)白:
#!/bin/bashset -o nounsetset -o errexit
這樣做會(huì)避免兩種常見(jiàn)的問(wèn)題:
引用未定義的變量(缺省值為“”)
執(zhí)行失敗的命令被忽略
需要注意的是,有些Linux命令的某些參數(shù)可以強(qiáng)制忽略發(fā)生的錯(cuò)誤,例如“mkdir -p” 和 “rm -f”。
還要注意的是,在“errexit”模式下,雖然能有效的捕捉錯(cuò)誤,但并不能捕捉全部失敗的命令,在某些情況下,一些失敗的命令是無(wú)法檢測(cè)到的。(更多細(xì)節(jié)請(qǐng)參考這個(gè)帖子。)
腳本函數(shù)
在bash里你可以定義函數(shù),它們就跟其它命令一樣,可以隨意的使用;它們能讓你的腳本更具可讀性:
ExtractBashComments() { egrep "^#"}cat myscript.sh | ExtractBashComments | wccomments=$(ExtractBashComments < myscript.sh)
還有一些例子:
SumLines() { # iterating over stdin - similar to awk local sum=0 local line=”” while read line ; do sum=$((${sum} + ${line})) done echo ${sum}}SumLines < data_one_number_per_line.txtlog() { ?# classic logger ?local prefix="[$(date +%Y/%m/%d\ %H:%M:%S)]: " ?echo "${prefix} $@" >&2}log "INFO" "a message"
盡可能的把你的bash代碼移入到函數(shù)里,僅把全局變量、常量和對(duì)“main”調(diào)用的語(yǔ)句放在最外層。
變量注解
Bash里可以對(duì)變量進(jìn)行有限的注解。最重要的兩個(gè)注解是:
local(函數(shù)內(nèi)部變量)
readonly(只讀變量)
# a useful idiom: DEFAULT_VAL can be overwritten# with an environment variable of the same namereadonly DEFAULT_VAL=${DEFAULT_VAL:-7}myfunc() {# initialize a local variable with the global default local some_var=${DEFAULT_VAL} ...}
這樣,你可以將一個(gè)以前不是只讀變量的變量聲明成只讀變量:
x=5x=6readonly xx=7 # failure
盡量對(duì)你bash腳本里的所有變量使用local或readonly進(jìn)行注解。
用$()代替反單引號(hào)(`)
反單引號(hào)很難看,在有些字體里跟正單引號(hào)很相似。$()能夠內(nèi)嵌使用,而且避免了轉(zhuǎn)義符的麻煩。
# both commands below print out: A-B-C-Decho "A-`echo B-\`echo C-\\\`echo D\\\`\``"echo "A-$(echo B-$(echo C-$(echo D)))"
用[[]](雙層中括號(hào))替代[]
使用[[]]能避免像異常的文件擴(kuò)展名之類的問(wèn)題,而且能帶來(lái)很多語(yǔ)法上的改進(jìn),而且還增加了很多新功能:
單中括號(hào):
[ "${name}" \> "a" -o ${name} \< "m" ]
雙中括號(hào)
[[ "${name}" > "a" && "${name}" < "m" ?]]
正則表達(dá)式/Globbing
使用雙中括號(hào)帶來(lái)的好處用下面幾個(gè)例子最能表現(xiàn):
t="abc123"[[ "$t" == abc* ]] # true (globbing比較)[[ "$t" == "abc*" ]] # false (字面比較)[[ "$t" =~ [abc]+[123]+ ]]# true (正則表達(dá)式比較)[[ "$t" =~ "abc*" ]] # false (字面比較)
注意,從bash 3.2版開(kāi)始,正則表達(dá)式和globbing表達(dá)式都不能用引號(hào)包裹。如果你的表達(dá)式里有空格,你可以把它存儲(chǔ)到一個(gè)變量里:
r="a b+"[[ "a bbb" =~ $r ]] # true
按Globbing方式的字符串比較也可以用到case語(yǔ)句中:
case $t inabc*)
字符串操作
Bash里有各種各樣操作字符串的方式,很多都是不可取的。
基本用戶
f="path1/path2/file.ext"len="${#f}" # = 20 (字符串長(zhǎng)度)# 切片操作: ${:
替換操作(使用globbing)
f="path1/path2/file.ext"single_subst="${f/path?/x}" # = "x/path2/file.ext"global_subst="${f//path?/x}" # = "x/x/file.ext"# 字符串拆分readonly DIR_SEP="/"array=(${f//${DIR_SEP}/ })second_dir="${arrray[1]}" # = path2
刪除頭部或尾部(使用globbing)
f="path1/path2/file.ext"# 刪除字符串頭部extension="${f#*.}" # = "ext"# 以貪婪匹配方式刪除字符串頭部filename="${f##*/}" # = "file.ext"# 刪除字符串尾部dirname="${f%/*}" # = "path1/path2"# 以貪婪匹配方式刪除字符串尾部root="${f%%/*}" # = "path1"
避免使用臨時(shí)文件
有些命令需要以文件名為參數(shù),這樣一來(lái)就不能使用管道。這個(gè)時(shí)候?<()?就顯出用處了,它可以接受一個(gè)命令,并把它轉(zhuǎn)換成可以當(dāng)成文件名之類的什么東西:
# 下載并比較兩個(gè)網(wǎng)頁(yè)diff <(wget -O - url1) <(wget -O - url2)
還有一個(gè)非常有用處的是”here documents”,它能讓你在標(biāo)準(zhǔn)輸入上輸入多行字符串。下面的’MARKER’可以替換成任何字詞。
# 任何字詞都可以當(dāng)作分界符command << MARKER...${var}$(cmd)...MARKER
如果文本里沒(méi)有內(nèi)嵌變量替換操作,你可以把第一個(gè)MARKER用單引號(hào)包起來(lái):
command << 'MARKER'...no substitution is happening here.$ (dollar sign) is passed through verbatim....MARKER
內(nèi)置變量
提示
使用$*很少是正確的選擇。
$@能夠處理空格參數(shù),而且參數(shù)間的空格也能正確的處理。
使用$@時(shí)應(yīng)該用雙引號(hào)括起來(lái),像”$@”這樣。
調(diào)試
對(duì)腳本進(jìn)行語(yǔ)法檢查:
bash -n myscript.sh
跟蹤腳本里每個(gè)命令的執(zhí)行:
bash -v myscripts.sh
跟蹤腳本里每個(gè)命令的執(zhí)行并附加擴(kuò)充信息:
bash -x myscript.sh
你可以在腳本頭部使用set -o verbose和set -o xtrace來(lái)永久指定-v和-o。當(dāng)在遠(yuǎn)程機(jī)器上執(zhí)行腳本時(shí),這樣做非常有用,用它來(lái)輸出遠(yuǎn)程信息。
什么時(shí)候不應(yīng)該使用bash腳本
你的腳本太長(zhǎng),多達(dá)幾百行
你需要比數(shù)組更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)
出現(xiàn)了復(fù)雜的轉(zhuǎn)義問(wèn)題
有太多的字符串操作
不太需要調(diào)用其它程序和跟其它程序管道交互
擔(dān)心性能
這個(gè)時(shí)候,你應(yīng)該考慮一種腳本語(yǔ)言,比如Python或Ruby。
-
Linux
+關(guān)注
關(guān)注
87文章
11304瀏覽量
209476 -
腳本
+關(guān)注
關(guān)注
1文章
389瀏覽量
14864
原文標(biāo)題:Linux Bash腳本15分鐘進(jìn)階教程
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論