日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

shell脚本——调试(-n / -x /-c)

發(fā)布時間:2025/10/17 编程问答 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 shell脚本——调试(-n / -x /-c) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

我們在前面介紹的調(diào)試手段是通過修改shell腳本的源代碼,從其輸出相關(guān)的調(diào)試信息來定位錯誤的,那有沒有不修改源代碼來調(diào)試shell腳本的方法呢?有的,那就是使用shell的執(zhí)行選項,下面將介紹一些常用選項的用法:

-n 只讀取shell腳本,但不實際執(zhí)行
-x 進入跟蹤方式,顯示所執(zhí)行的每一條命令
-c "string" strings中讀取命令

"-n"可用于測試shell腳本是否存在語法錯誤,但不會實際執(zhí)行命令。shell腳本編寫完成之后,實際執(zhí)行之前,首先使用"-n"選項來測試腳本是否存在語法錯誤是一個很好的習慣。因為某些shell腳本在執(zhí)行時會對系統(tǒng)環(huán)境產(chǎn)生影響,比如生成或移動文件等,如果在實際執(zhí)行才發(fā)現(xiàn)語法錯誤,您不得不手工做一些系統(tǒng)環(huán)境的恢復工作才能繼續(xù)測試這個腳本。

"-c"選項使shell解釋器從一個字符串中而不是從一個文件中讀取并執(zhí)行shell命令。當需要臨時測試一小段腳本的執(zhí)行結(jié)果時,可以使用這個選項,如下所示:
sh -c 'a=1;b=2;let c=$a+$b;echo "c=$c"'

"-x"選項可用來跟蹤腳本的執(zhí)行,是調(diào)試shell腳本的強有力工具。"-x"選項使shell在執(zhí)行腳本的過程中把它實際執(zhí)行的每一個命令行顯示出來,并且在行首顯示一個"+"號。 "+"號后面顯示的是經(jīng)過了變量替換之后的命令行的內(nèi)容,有助于分析實際執(zhí)行的是什么命令。 "-x"選項使用起來簡單方便,可以輕松對付大多數(shù)的shell調(diào)試任務,應把其當作首選的調(diào)試手段。


如果把本文前面所述的trap ‘command’ DEBUG機制與“-x”選項結(jié)合起來,我們就可以既輸出實際執(zhí)行的每一條命令,又逐行跟蹤相關(guān)變量的值,對調(diào)試相當有幫助。

我們以debug.sh腳本為例:

# cat -n debug.sh??

1 #!/bin/sh2 trap 'echo "before execute line:$LINENO,a=$a,b=$b,c=$c"' DEBUG3 a=14 if [ "$a" -eq 1 ]5 then 6 b=27 else 8 b=19 fi10 c=311 echo end

現(xiàn)在對該腳本加上“-x”選項來執(zhí)行它:

當?shù)?行被注釋掉?當?shù)?行沒有被注釋掉(即代碼中有trap命令)

在上面的結(jié)果中,前面有“+”號的行是shell腳本實際執(zhí)行的命令,前面有“++”號的行是執(zhí)行trap機制中指定的命令,其它的行則是輸出信息。

shell的執(zhí)行選項除了可以在啟動shell時指定外,亦可在腳本中用set命令來指定。 "set -?參數(shù)"表示啟用某選項,"set +參數(shù)"表示關(guān)閉某選項。有時候我們并不需要在啟動時用"-x"選項來跟蹤所有的命令行,這時我們可以在腳本中使用set命令,如以下腳本片段所示:

set -x#啟動"-x"選項
要跟蹤的程序段
set +x#關(guān)閉"-x"選項

set命令同樣可以使用前面介紹的調(diào)試鉤子—DEBUG函數(shù)來調(diào)用,下面是DEBUG函數(shù)代碼:
#cat –n debugOth.sh?

#!/bin/sh DEBUG() {if [ "DEBUG"="true" ];then$@fi } a=1 DEBUG echo "a=$a" if [ "$a" -eq 1 ] then b=2 else b=1 fi DEBUG echo "b=$b" c=3 DEBUG echo "c=$c"
$@與$*相同,但是使用時加引號,并在引號中返回每個參數(shù)。
如"$@"用「"」括起來的情況、以"$1" "$2" … "$n" 的形式輸出所有參數(shù)。
這樣可以避免腳本交付使用時刪除這些調(diào)試語句的麻煩,如以下腳本片段所示:

DEBUG set -x#啟動"-x"選項
要跟蹤的程序段

DEBUG set +x#關(guān)閉"-x"選項

# sh debugOth.sh# sh -x debugOth.sh

. "-x"選項的增強

"-x"執(zhí)行選項是目前最常用的跟蹤和調(diào)試shell腳本的手段,但其輸出的調(diào)試信息僅限于進行變量替換之后的每一條實際執(zhí)行的命令以及行首的一個"+" 號提示符,居然連行號這樣的重要信息都沒有,對于復雜的shell腳本的調(diào)試來說,還是非常的不方便。幸運的是,我們可以巧妙地利用shell內(nèi)置的一些環(huán)境變量來增強"-x"選項的輸出信息,下面先介紹幾個shell內(nèi)置的環(huán)境變量:

$LINENO
代表shell腳本的當前行號,類似于C語言中的內(nèi)置宏__LINE__

$FUNCNAME
函數(shù)的名字,類似于C語言中的內(nèi)置宏__func__,但宏__func__只能代表當前所在的函數(shù)名,而$ FUNCNAME的功能更強大,它是一個數(shù)組變量,其中包含了整個調(diào)用鏈上所有的函數(shù)的名字,故變量${FUNCNAME[0]}代表shell腳本當前正在執(zhí)行的函數(shù)的名字,而變量${FUNCNAME[1]}則代表調(diào)用函數(shù)${FUNCNAME[0]}的函數(shù)的名字,余者可以依此類推。

$PS4
主提示符變量$PS1和第二級提示符變量$PS2比較常見,但很少有人注意到第四級提示符變量$PS4的作用。我們知道使用“- x”執(zhí)行選項將會顯示shell腳本中每一條實際執(zhí)行過的命令,而$PS4的值將被顯示在“-x”選項輸出的每一條命令的前面。在Bash?Shell中,缺省的$PS4的值是"+"號。(現(xiàn)在知道為什么使用"-x"選項時,輸出的命令前面有一個"+"號了吧?)

利用$PS4這一特性,通過使用一些內(nèi)置變量來重定義$PS4的值,我們就可以增強"-x"選項的輸出信息。例如先執(zhí)行export PS4='+{$LINENO:${FUNCNAME[0]}} ', 然后再使用“-x”選項來執(zhí)行腳本,就能在每一條實際執(zhí)行的命令前面顯示其行號以及所屬的函數(shù)名。

以下是一個存在bugshell腳本的示例,本文將用此腳本來示范如何用“-n”以及增強的“-x”執(zhí)行選項來調(diào)試shell腳本。這個腳本中定義了一個函數(shù)isRoot(),用于判斷當前用戶是不是root用戶,如果不是,則中止腳本的執(zhí)行。

# cat -n debugOthO.sh

1 #!/bin/sh2 isRoot()3 {4 if [ "$UID" -ne 0 ]5 return 16 else7 return 08 fi9 }10 isRoot11 if ["$?" -ne 0]12 then13 echo "Must be root to run this script"14 exit 115 else16 echo "welcome root user"17 #do something18 fi

首先執(zhí)行# sh -n debugOthO.sh來進行語法檢查,輸出如下:
# sh -n debugOthO.sh
exp4.sh: line 6: syntax error near unexpected token `else'
exp4.sh: line 6: ` else'

發(fā)現(xiàn)了一個語法錯誤,通過仔細檢查第6行前后的命令,我們發(fā)現(xiàn)是第4行的if語句缺少then關(guān)鍵字引起的(寫慣了C程序的人很容易犯這個錯誤)。我們可以把第4行修改為if [ "$UID" -ne 0 ]; then來修正這個錯誤。再次運行# sh -n debugOthO.sh來進行語法檢查,沒有再報告錯誤。接下來就可以實際執(zhí)行這個腳本了,執(zhí)行結(jié)果如下:

# sh -n debugOthO.sh
exp2.sh: line 11: [1: command not found
welcome root user

盡管腳本沒有語法錯誤了,在執(zhí)行時卻又報告了錯誤。錯誤信息還非常奇怪“[1: command not found”。現(xiàn)在我們可以試試定制$PS4的值,并使用“-x”選項來跟蹤:

$ export PS4='+{$LINENO:${FUNCNAME[0]}} '
$ sh –x debugOthO.sh

+{10:} isRoot
+{4:isRoot} '[' 503 -ne 0 ']'
+{5:isRoot} return 1
+{11:} '[1' -ne 0 ']'
exp4.sh: line 11: [1: command not found
+{16:} echo 'welcome root user'
welcome root user

從輸出結(jié)果中,我們可以看到腳本實際被執(zhí)行的語句,該語句的行號以及所屬的函數(shù)名也被打印出來,從中可以清楚的分析出腳本的執(zhí)行軌跡以及所調(diào)用的函數(shù)的內(nèi)部執(zhí)行情況。由于執(zhí)行時是第11行報錯,這是一個if語句,我們對比分析一下同為if語句的第4行的跟蹤結(jié)果:

+{4:isRoot} '[' 503 -ne 0 ']'
+{11:} '[1' -ne 0 ']'

到這里我們就知道由于第11行的[號后面缺少了一個空格,導致[號與緊挨它的變量$?的值1shell解釋器看作了一個整體,并試著把這個整體視為一個命令來執(zhí)行,故有“[1: command not found”這樣的錯誤提示。只需在[號后面插入一個空格就一切正常了。

shell中還有其它一些對調(diào)試有幫助的內(nèi)置變量,比如在Bash Shell中還有BASH_SOURCE, BASH_SUBSHELL等一批對調(diào)試有幫助的內(nèi)置變量,您可以通過man shman bash來查看,然后根據(jù)您的調(diào)試目的,使用這些內(nèi)置變量來定制$PS4,從而達到增強“-x”選項的輸出信息的目的。

. 總結(jié)

現(xiàn)在讓我們來總結(jié)一下調(diào)試shell腳本的過程:
首先使用“-n”選項檢查語法錯誤,然后使用“-x”選項跟蹤腳本的執(zhí)行,使用“-x”選項之前,別忘了先定制PS4變量的值來增強“-x”選項的輸出信息,至少應該令其輸出行號信息(先執(zhí)行export PS4='+[$LINENO]',更一勞永逸的辦法是將這條語句加到您用戶主目錄的.bash_profile文件中去),這將使你的調(diào)試之旅更輕松。也可以利用trap,調(diào)試鉤子等手段輸出關(guān)鍵調(diào)試信息,快速縮小排查錯誤的范圍,并在腳本中使用“set -x”“set +x”對某些代碼塊進行重點跟蹤。這樣多種手段齊下,相信您已經(jīng)可以比較輕松地抓出您的shell腳本中的臭蟲了。
如果您的腳本足夠復雜,還需要更強的調(diào)試能力,可以使用shell調(diào)試器bashdb,這是一個類似于GDB的調(diào)試工具,可以完成對shell腳本的斷點設置,單步執(zhí)行,變量觀察等許多功能,使用bashdb對閱讀和理解復雜的shell腳本也會大有裨益。關(guān)于bashdb安裝和使用,不屬于本文范圍,您可參閱http://bashdb.sourceforge.net/上的文檔并下載試用


參考鏈接:

http://www.360doc.com/content/17/0706/19/33093582_669392362.shtml



總結(jié)

以上是生活随笔為你收集整理的shell脚本——调试(-n / -x /-c)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。