shell 腳本常用調試方法

曾經我剛開始學習 shell 腳本時,除了知道用 echo 輸出一些信息外,並不知道其他方法,僅僅依賴 echo 來查找錯誤,比較難調試且過程繁瑣、效率低下。本文介紹下我常用的一些 shell 腳本調試方法,希望能對 shell 的初學者有所幫助。

sh 命令調試選項(推薦)

選項 說明
-c -c後的字符串中讀取命令。
-n 檢查是否存在語法錯誤,但不會實際執行。
-x 將執行的每一條命令和結果依次打印出來。
-v 執行過的腳本命令打印到標準輸出。

使用方法:

字符串讀取腳本。

$ sh -c 'if [ 1 -lt 2 ];then echo "true"; else echo "false"; fi'
true

注:臨時測試 shell 語法或者小段腳本時使用。

檢查腳本是否存在語法錯誤。

$ 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 方法

在腳本中用set命令。

  • set -xv表示啓用;
  • set +xv表示禁用。

使用方法:

$ 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可以進行局部調試,在需要調試的代碼塊前後設置即可。

工具

shellcheck

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...

BASH Debugger

bashdb 是一個類 GDB 的調試工具,可以運行斷點設置、變量查看等常見調試操作。

官網:http://bashdb.sourceforge.net/

常用參數:

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...

微信公衆號:daodaotest

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章