bash中的腳本調試機制

以調試模式運行腳本

經過bash -x <script>的方式能夠在調試模式下運行整個腳本, bash會在在運行前打印出了每一行命令, 並且每行前面用+號代表命令的嵌套層數.linux

> bash -x debug.sh 
+ echo 'First line'
First line  # 輸出結果沒有加號
++ date  # 先執行命令替換 兩個加號是由於該命令嵌套在echo中
+ echo 'Print datetime: Thu 26 Mar 2020 08:21:28 PM CST Done.'
Print datetime: Thu 26 Mar 2020 08:21:28 PM CST Done.

若是腳本比較複雜, 咱們能夠經過使用環境變量PS4配合調試用的內置變量用於輸出更加詳細的信息:shell

> export PS4='+${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]}: '
> bash -x debug.sh 
+debug.sh:3:: echo 'First line'
First line
++debug.sh:4:: date
+debug.sh:4:: echo 'Print datetime: Thu 26 Mar 2020 08:35:59 PM CST Done.'
Print datetime: Thu 26 Mar 2020 08:35:59 PM CST Done.

咱們也可使用trapDEBUG關鍵字在解釋執行每一行腳本以前執行指定的命令或函數:bash

trap 'echo "VARIABLE-TRACE> \$variable = \"$variable\""' DEBUG
variable=29
let variable++
let variable*=5
exit 0

# 輸出以下
VARIABLE-TRACE> $variable = ""
VARIABLE-TRACE> $variable = "29"
VARIABLE-TRACE> $variable = "30"
VARIABLE-TRACE> $variable = "150"

還可使用trapERR關鍵字用於在解釋出現錯誤時執行預設的操做, 例如打印出錯的命令:函數

trap 'echo $BASH_COMMAND' ERR

但鑑於使用trap進行調試的執行效率太低, 建議在較爲複雜的腳本中直接使用調試選項或者使用bashdb等調試工具.工具

高級調試

查看函數調用信息

在函數中使用內置命令caller可以把函數的調用信息輸出到stdout, 但要注意該命令必須在函數內部調用.this

#!/usr/bin/bash

func1 () {
    for i in `seq 0 3`
    do
        echo -e "Level$i\t    `caller $i`"
    done
}

func2 () {
    func1
}

func3 () {
    func2
}

func3
caller 0  # 必須在函數中調用 不然無輸出
exit 0

運行該腳本能夠獲得如下輸出:命令行

Level0      11 func2 call.sh  # func1 的直接調用者
Level1      15 func3 call.sh  # 一層間接調用
Level2      18 main call.sh   # 二層間接調用
Level3      # 無輸出 由於沒有第三層調用

局部調試

能夠經過set命令構造局部調試塊,咱們能夠按照以下方式添加局部調試:debug

set -x
date
set +x
> bash script1.sh  # 不須要添加調試參數
The script starts now. 

+ date
Fri 28 Feb 2020 06:23:04 PM CST
+ set +x

This is a string: black
And this is a number: 9

調試參數表

短命令 長命令 效果
set -f set -o noglob 對文件名停用元字符匹配
set -v set -o verbose 打印輸入的命令
set -x set -o xtrace 命令行首打印+,執行出錯會打印詳細信息

調試用的參數能夠在運行中動態疊加或刪除:調試

> set -v
> date
date  
Fri 28 Feb 2020 06:54:47 PM CST
> set -x            # 參數能夠累加
date                # -v 的效果
+ date              # -x 的效果
Fri 28 Feb 2020 06:55:37 PM CST
> set +vx           # 取消參數
set +vx

經過使用-f選項能夠顯著減小腳本中的轉義字符:code

> ls ?
x86_64-pc-linux-gnu-library
> set -f            # 停用元字符匹配
> ls ?
ls: cannot access '?': No such file or directory
> touch ?
> ls ?
'?'
> rm ?
> set +f -x      # 選項 x 還能夠用於顯示詳細錯誤信息
> aaa
+ aaa
+ '[' -x /usr/lib/command-not-found ']'
+ /usr/lib/command-not-found -- aaa

Command 'aaa' not found, did you mean:

  command 'aha' from deb aha (0.5-1)
  command 'jaaa' from deb jaaa (0.8.4-4)
  command 'aa' from deb astronomical-almanac (5.6-6)

Try: sudo apt install <deb name>

+ return 127

默認調試

也能夠直接在腳本第一行添加參數讓腳本默認以調試模式啓動:

#!/bin/bash -xv

還能夠在可能出錯的命令前用echo輸出調試信息:

echo "debug message: now attempting to start w command"; w  # 用 ; 對要執行的命令排序
echo "Variable VARNAME is now set to $VARNAME."

設置選項輔助調試

爲了方便調試,咱們可使用set命令對bash的選項進行設置:

> set -o  # 查看全部選項的開關狀態
> set -o | grep xtrace
xtrace          off
> set -x  # 等價於 set -o xtrace
> set -o | grep xtrace 
+ grep --color=auto xtrace
+ set -o
xtrace          on
> set +x  # 等價於 set +o xtrace
+ set +x
> set -o | grep xtrace
xtrace          off

經常使用調試選項

引用爲定義變量時報錯:

> unset $VAR;echo $VAR

> set -u  # 等價於 set -o nounset
> echo $var
bash: var: unbound variable

爲防止誤操做覆蓋文件中的數據, 設置禁止重定向到已經存在的文件:

> set -C  # 等價於 set -o noclobber
> touch test
> date > test
bash: test: cannot overwrite existing file

設置不解析通配符:

> set -f  # 等價於 set -o noglob
> touch *
> ll *
-rw-rw-r-- 1 remilia remilia 0 Mar  1 20:09 '*'
相關文章
相關標籤/搜索