曾經我剛開始學習 shell 腳本時,除了知道用 echo 輸出一些信息外,並不知道其餘方法,僅僅依賴 echo 來查找錯誤,比較難調試且過程繁瑣、效率低下。本文介紹下我經常使用的一些 shell 腳本調試方法,但願能對 shell 的初學者有所幫助。git
選項 | 說明 |
---|---|
-c | 從-c 後的字符串中讀取命令。 |
-n | 檢查是否存在語法錯誤,但不會實際執行。 |
-x | 將執行的每一條命令和結果依次打印出來。 |
-v | 執行過的腳本命令打印到標準輸出。 |
使用方法:github
字符串讀取腳本。shell
$ sh -c 'if [ 1 -lt 2 ];then echo "true"; else echo "false"; fi' true
注:臨時測試 shell 語法或者小段腳本時使用。bash
檢查腳本是否存在語法錯誤。koa
$ sh -n daodaotest.sh
跟蹤調試 shell 腳本,將執行的每一條命令結果依次打印出來。工具
$ sh -x daodaotest.sh + '[' 2 -lt 2 ']' + COUNT=3 + PARAMETER=daodaotest + (( i = 1 )) + (( i <= 3 )) + echo '第 1 遍打印:daodaotest' 第 1 遍打印:daodaotest + (( i++ )) + (( i <= 3 )) + echo '第 2 遍打印:daodaotest' 第 2 遍打印:daodaotest + (( i++ )) + (( i <= 3 )) + echo '第 3 遍打印:daodaotest' 第 3 遍打印:daodaotest + (( i++ )) + (( i <= 3 )) + exit 0
跟蹤調試 shell 腳本,將執行的每一條命令和結果依次打印出來。學習
$ sh -xv daodaotest.sh #!/bin/bash # 調試腳本示例 # 使用方法 usage() { echo "Usage: sh $0 COUNT PARAMETER" echo "\t COUNT 循環打印次數" echo "\t PARAMETER 打印字符串" echo "示例:" echo "\t 1. 打印 daodaotest 2 次" echo "\t sh $0 2 daodaotest" } # 判斷參數 if [ $# -lt 2 ]; then usage exit 1 fi + '[' 2 -lt 2 ']' # 打印次數 COUNT=$1 + COUNT=3 # 打印字符串 PARAMETER=$2 + PARAMETER=daodaotest # 循環打印 for (( i = 1; i <= $COUNT; i++)); do echo "第 $i 遍打印:$PARAMETER" done + (( i = 1 )) + (( i <= 3 )) + echo '第 1 遍打印:daodaotest' 第 1 遍打印:daodaotest + (( i++ )) + (( i <= 3 )) + echo '第 2 遍打印:daodaotest' 第 2 遍打印:daodaotest + (( i++ )) + (( i <= 3 )) + echo '第 3 遍打印:daodaotest' 第 3 遍打印:daodaotest + (( i++ )) + (( i <= 3 )) exit 0 + exit 0
注:本人最經常使用-x
參數,能解決 90% 的腳本調試問題。測試
在腳本中用set
命令。ui
set -xv
表示啓用;set +xv
表示禁用。使用方法:.net
$ cat daodaotest.sh set -xv ..... 省略 set +xv $ sh daodaotest.sh 2 daodaotest # 使用方法 usage() { echo "Usage: sh $0 COUNT PARAMETER" echo "\t COUNT 循環打印次數" echo "\t PARAMETER 打印字符串" echo "示例:" echo "\t 1. 打印 daodaotest 2 次" echo "\t sh $0 2 daodaotest" } # 判斷參數 if [ $# -lt 2 ]; then usage exit 1 fi + '[' 2 -lt 2 ']' # 打印次數 COUNT=$1 + COUNT=2 # 打印字符串 PARAMETER=$2 + PARAMETER=daodaotest # 循環打印 for (( i = 1; i <= $COUNT; i++)); do echo "第 $i 遍打印:$PARAMETER" done + (( i = 1 )) + (( i <= 2 )) + echo '第 1 遍打印:daodaotest' 第 1 遍打印:daodaotest + (( i++ )) + (( i <= 2 )) + echo '第 2 遍打印:daodaotest' 第 2 遍打印:daodaotest + (( i++ )) + (( i <= 2 )) exit 0 + exit 0
注: 在腳本很是複雜時,set
能夠進行局部調試,在須要調試的代碼塊先後設置便可。
shell 腳本靜態檢查工具,能夠幫助你寫出恰好的腳本。
官網:https://www.shellcheck.net/
手冊:https://github.com/koalaman/shellcheck
使用方法:
$ shellcheck daodaotest.sh In daodaotest.sh line 8: echo "\t COUNT 循環打印次數" ^---------------^ SC2028: echo may not expand escape sequences. Use printf. In daodaotest.sh line 9: echo "\t PARAMETER 打印字符串" ^------------------^ SC2028: echo may not expand escape sequences. Use printf. In daodaotest.sh line 11: echo "\t 1. 打印 daodaotest 2 次" ^-----------------------^ SC2028: echo may not expand escape sequences. Use printf. In daodaotest.sh line 12: echo "\t sh $0 2 daodaotest" ^---------------------^ SC2028: echo may not expand escape sequences. Use printf. In daodaotest.sh line 28: for (( i = 1; i <= $COUNT; i++)); ^----^ SC2004: $/${} is unnecessary on arithmetic variables. For more information: https://www.shellcheck.net/wiki/SC2028 -- echo may not expand escape sequen... https://www.shellcheck.net/wiki/SC2004 -- $/${} is unnecessary on arithmeti...
bashdb 是一個類 GDB 的調試工具,能夠運行斷點設置、變量查看等常見調試操做。
經常使用參數:
h:查看幫助。 help 命令:命令的具體信息。 n:執行下一條語句。 s n:單步執行 n 次。 b n:在行號 n 處設置斷點。 c n:一直執行到行號 n 處。 l:顯示上下文代碼。 print:打印變量值,例如 print $COUNT。 finish:執行到程序最後或斷點處。 q or exit:退出。 R:從新執行。
使用方法:
$ bashdb --debug daodaotest.sh bash debugger, bashdb, release 5.0-1.1.2 Copyright 2002-2004, 2006-2012, 2014, 2016-2019 Rocky Bernstein This is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. (/Users/jlh/tmp/daodaotest.sh:15): 15: if [ $# -lt 2 ]; # 執行下一條語句。 bashdb<0> n (/Users/jlh/tmp/daodaotest.sh:22): 22: COUNT=$1 # 顯示上下文代碼。 bashdb<1> l 17: usage 18: exit 1 19: fi 20: 21: # 打印次數 22: => COUNT=$1 23: # 打印字符串 24: PARAMETER=$2 25: 26: # 循環打印 # 單步執行 3 次。 bashdb<2> s 3 (/Users/jlh/tmp/daodaotest.sh:27): 27: for (( i = 1; i <= $COUNT; i++)); ((i <= 3)) bashdb<3> l 22: COUNT=$1 23: # 打印字符串 24: PARAMETER=$2 25: 26: # 循環打印 27: => for (( i = 1; i <= $COUNT; i++)); 28: do 29: echo "第 $i 遍打印:$PARAMETER" 30: done 31: # 打印 $COUNT 參數值 bashdb<4> print $COUNT 3 # 執行到最後 bashdb<5> finish 第 1 遍打印:daodaotest 第 2 遍打印:daodaotest 第 3 遍打印:daodaotest Debugged program terminated normally. Use q to quit or R to restart. # 退出 bashdb<6> q bashdb: That's all, folks...