shell程式設計之DRY&KISS
用BASH程式設計已有些時間了,參與過大型專案的開發。當初的摸石子過河,專案越來越大了,程式碼開始腐朽了。
也許,從新開始是件好事,如同老闆所說,背上太多的包袱,你如何前行!
下面,我從DRY(Dont’t Repeat Yourself)和KISS(Keep it Simple & Smart),這兩條
最重要的程式設計原則來展示一下我在新專案中的實踐。
1. assert
及時發現錯誤,C程式碼中assert就是這樣一個用處,很多時間,我們的程式設計師並不對命
令的執行進行返回碼檢查,其主要原因是,怕麻煩,且使用大量的if判斷增加了程式碼
的冗餘,如下所示。
[code lang=”shell”]function fn_main() {
cp $src $dst
if [ $? -ne 0 ]; then
echo "cp fail"
return 1
fi
}[/code]
我們可以構造一個BASH版的assert,稱其為xt(assert的縮寫)
[code lang=”shell”]PS8="eval echo \${BASH_SOURCE##*/}\|\$LINENO\|: "
function xt() {
[ "${1}" -eq 0 ] && return ${1}
echo ${@:2} || return $?
return ${1}
}[/code]
那麼上面的程式碼改寫如下:
[code lang=”shell”]function fn_main() {
cp $src $dst
xt $? `$PS8` "cp fail" || return $?
}[/code]
使用xt有兩個明顯的好處:
a. 大大減少檢查程式碼的行數
b. 函式呼叫層次較多時,如果出錯了,可以打印出呼叫棧
2. 關於日誌
當前的程式碼現狀:
a. 寫程式碼時不寫日誌
b. 只有自己的提示資訊,沒有錯誤輸出,往往命令的錯誤輸出才是查錯的關鍵
[code lang=”shell”]function fn_main() {
fn_cp $src1 $dst1 # 沒有日誌
fn_cp $src2 $dst2 || echo "cp fail" > $logfile # 不小心把日誌清空了
fn_cp $src3 $dst3 || echo "cp fail" >> $logfile # 無錯誤輸出
fn_cp $src4 $dst4 || echo "cp fail" >> $logfile 2>&1 # 寫得太多,麻煩
}[/code]
結合xt,我們可以給出更好的方案
[code lang=”shell”]function fn_main() {
fn_cp $src1 $dst1
xt $? `$PS8` "cp fail" || return $?
}
fn_main [email protected] | tee -a $logfile
ret=$PIPESTATUS[0]
exit $ret[/code]
3. KISS,我們可以使用全域性變數
先看一下老程式碼:
[code lang=”shell”]function fn_get_keys_from_conf() {
key1=`fn_get_val key1`
key2=`fn_get_val key2`
key3=`fn_get_val key3`
}
function fn_proc1() {
local key1=$1
local key2=$2
local key3=$3
}
.
.
.
function fn_procn() {
local key1=$1
local key2=$2
local key3=$3
}
function fn_main() {
fn_get_keys_from_conf
fn_proc1 $key1 $key2 $key3
fn_proc2 $key1 $key2 $key3
fn_proc3 $key1 $key2 $key3
}
fn_main[/code]
變數如果沒有local限定詞,其屬性預設為全域性的,使用local區域性變數可以使變數
使用更加安全,但是帶來大量冗餘與重複,導致失誤操作增加。
大多時候,從配置檔案中讀取的配置都是隻讀的,為了安全,我們只要使用關鍵字
readonly就可以保證其安全了。而且我們可以把所有全域性變數放在一起管理。
那麼上面的程式碼這樣就可以了:
[code lang=”shell”]function fn_get_keys_from_conf()
{
readonly key1=`fn_get_val key1`
readonly key2=`fn_get_val key2`
readonly key3=`fn_get_val key3`
}
function fn_main()
{
fn_get_keys_from_conf
fn_proc1
fn_proc2
fn_proc3
}
fn_main[/code]
後記:使用已有特性DIY解決應用過程中的問題,不斷優化,如此才有進步。不斷的重複自己,只會讓人變懶變傻。