Bash指令碼debug攻略

王bourne發表於2022-07-14

初學Bash時, 我從未想過去debug Bash指令碼, 也從未想過Bash指令碼也能debug. 隨著技術的增長, 寫的指令碼越來越複雜, 使用echo列印日誌來除錯指令碼的方式越來越捉襟見肘了. 直到某天
通讀了一遍Bash Reference Manual, 才發現Bash指令碼也是可以debug的. 下面就介紹三種debug Bash指令碼的方式.

1. debug某個指令碼

執行指令碼有兩種方式, 一是bash script.sh的方式, 二是./script.sh的方式. 通過第一種方式執行指令碼時, 加上-x選項即可debug指令碼.
輸出的結果中, 以+開頭的行就是debug輸出的資訊.

$ cat test.sh
#!/bin/bash

echo "Time: $(date)"
echo "User: $USER"
echo "Home: $HOME"

$ bash -x test.sh 
++date
+echo 'Time: Mon 11 Jul 2022 11:29:37 PM CST'
Time: Mon 11 Jul 2022 11:29:37 PM CST
+echo 'User: wbourne '
User: wbourne 
+echo 'Home: /home/wbourne '
Home: /home/wbourne 

2. debug特定指令碼

前面說過執行指令碼有兩種方式, 那如果是用第二種方式執行指令碼如何debug呢? 修改指令碼的shabangbash -x即可. 每次執行指令碼就會輸出debug資訊.
此方式適合debug某個特定的指令碼, 執行指令碼時會預設輸出debug資訊; 而上面的第一種方式則適合debug任何指令碼.

$ cat test.sh
#!/bin/bash -x

echo "Time: $(date)"
echo "User: $USER"
echo "Home: $HOME"

$ ./test.sh 
++date
+echo 'Time: Mon 11 Jul 2022 11:32:52 PM CST'
Time: Mon 11 Jul 2022 11:32:52 PM CST
+echo 'User: wbourne '
User: wbourne
+echo 'Home: /home/wbourne '
Home: /home/wbourne

請注意: 如果修改指令碼的shabang為bash -x, 又以bash script.sh的方式執行指令碼, 會發生什麼? 居然沒有輸出debug資訊!!!
設定shabang表示設定一個預設直譯器, 如果沒有指定直譯器才會使用shabang中寫的直譯器. 以bash script.sh的方式執行指令碼則指定了直譯器為bash, 所以不會有debug資訊.

$ bash test.sh 
Time: Mon 11 Jul 2022 11:32:12 PM CST
User: wbourne 
Home: /home/wbourne 

3. debug指令碼某一部分

如果指令碼比較長, 我們之關心其中一部分, 就可以使用Bash內建命令set來debug部分指令碼.
set -x表示開啟debug, set +x表示關閉debug

$ cat test.sh
#!/bin/bash

echo "Time: $(date)"
set -x
echo "User: $USER"
set +x
echo "Home: $HOME"

$ ./test.sh 
Time: Mon 11 Jul 2022 11:33:43 PM CST
+echo 'User: wbourne '
User: wbourne 
+set +x
Home: /home/wbourne 

4. PS4

既然是debug, 那肯定要詳細才好. 上述debug只不過是輸出了變數值而已, 是不是可以顯示更多資訊? 當然是可以的, debug資訊的提示符是環境變數PS4, 預設為+, 我們可以更改PS4的值, 使其輸出指令碼名, 函式名, 行數等更詳細的資訊. 這個提示符還是綠色的哦!

$ echo $PS4
+

$ export PS4='+\e[01;32m[${BASH_SOURCE}:${FUNCNAME[0]}:${LINENO}]\e[00m'

$ bash -x test.sh 
++[test.sh::3]date
+[test.sh::3]echo 'Time: Mon 11 Jul 2022 11:35:08 PM CST'
Time: Mon 11 Jul 2022 11:35:08 PM CST
+[test.sh::4]echo 'User: wbourne '
User: wbourne 
+[test.sh::5]echo 'Home: /home/wbourne '
Home: /home/wbourne 

5. 參考

相關文章