1. 程式人生 > >【linux】shell指令碼除錯技術

【linux】shell指令碼除錯技術

在使用gcc編譯keepalived原始碼的時候,需要執行configure生成Makefile,然後用make命令編譯。但是在這個過程中,configure檔案卻一直無法掃描到一個已經安裝的三方庫。無奈,只能檢視configure原始碼。configure其實就是一個shell指令碼,為了幫助理解指令碼,使用了一些除錯技術。在此做個介紹。

以下內容絕大部分參考:
Shell指令碼除錯技術

測試指令碼test.sh

[email protected]:~$ cat test.sh
a=1
if [ "$a" -eq 1 ]
then
        b=2
else
b=1 fi c=3 echo "end"

使用sh -x test.sh執行指令碼。

預設會直接輸出到螢幕,使用以下命令重定向到檔案。
sh -x test.sh &> log.txt
輸出如下:

[email protected]:~$ sh -x  test.sh
+ a=1
+ [ 1 -eq 1 ]
+ b=2
+ c=3
+ echo end
end

在上面的結果中,前面有“+”號的行是shell指令碼實際執行的命令,前面有“++”號的行是執行trap機制中指定的命令(如果指令碼不使用trap語句就不會列印++嗎?輸出不是由PS4變數決定的嗎?不太懂),其它不帶+的行則是輸出資訊。

-x 增強
“-x”執行選項是目前最常用的跟蹤和除錯shell指令碼的手段,但其輸出的除錯資訊僅限於進行變數替換之後的每一條實際執行的命令以及行首的一個”+”號提示符,居然連行號這樣的重要資訊都沒有,對於複雜的shell指令碼的除錯來說,還是非常的不方便。幸運的是,我們可以巧妙地利用shell內建的一些環境變數來增強”-x”選項的輸出資訊,下面先介紹幾個shell內建的環境變數:

$LINENO
代表shell指令碼的當前行號,類似於C語言中的內建巨集LINE

$FUNCNAME
函式的名字,類似於C語言中的內建巨集func,但巨集func只能代表當前所在的函式名,而

CNAME的功能更强大,它是一个数组变量,其中包含了整个调用链上所有的函数的名字,故变量" role="presentation"> F U N C N A M E 調 {FUNCNAME[0]}代表shell腳本當前正在執行的函式的名字,而變數 F U N C N A M E [ 1 ] 調 {FUNCNAME[0]}的函式的名字,餘者可以依此類推。

P S 4 PS1和第二級提示符變數 P S 2 PS4的作用。我們知道使用“-x”執行選項將會顯示shell指令碼中每一條實際執行過的命令,而 P S 4 x B a s h S h e l l PS4的值是”+”號。(現在知道為什麼使用”-x”選項時,輸出的命令前面有一個”+”號了吧?)。

利用 P S 4 使 PS4的值,我們就可以增強”-x”選項的輸出資訊。例如先執行export PS4=’+{ L I N E N O : {FUNCNAME[0]}} ‘, 然後再使用“-x”選項來執行指令碼,就能在每一條實際執行的命令前面顯示其行號以及所屬的函式名。

在設定了這個PS4這個變數之後,再執行sh -x test.sh,一直報錯:

Bad substitution

執行bash -x test.sh即OK,輸出了行號加函式。沒有深入去了解其中原因以及sh與bash具體的不同。

[email protected]:~$ bash -x  test.sh
+{2:main}   a=1
+{3:main}   '[' 1 -eq 1 ']'
+{5:main}   b=2
+{9:main}   c=3
+{10:main}   echo end
end

有了這個利器,還有啥問題搞不定,太讚了。果然是工欲善其事,必先利其器。

其他除錯技術

雖然覺得-x 就可以搞定一切了。但是還是記一些其他的除錯技術,以防將來用到。

-n 不真正執行指令碼,只檢查語法。
trap 滿足某些條件時,列印日誌
使用除錯鉤子 即定義DEBUG變數,通過這個變數的值來決定是否列印日誌。

具體都請參考原文:
Shell指令碼除錯技術