看到 CIH 介紹了一個 debug Shell Script 技巧,在大量 debug 時候,不需要再拼命塞一堆echo在程式碼。

方法很簡單,只需要輸入

$ (exec 111> log ;
export SHELLOPTS BASH_XTRACEFD=111 PS4='($BASH_SOURCE:$LINENO:$FUNCNAME): ' ;
set -x ; ./cih.sh)

作用是

  1. exec 111> log:這條命令打開一個名為 log 的文件用於寫入,並將它關聯到file descriptor 111 上。這意味著接下來的輸出可以被重定向到這個文件。
  2. export SHELLOPTS:這條命令將當前 shell 的選項導出為環境變量,使得子 shell 也能繼承這些選項。
  3. BASH_XTRACEFD=111:這是一個環境變量,用於指定當 set -x 啟用時,所有的 trace 輸出應該被寫入哪個 descriptor。在這裡,它被設定為 111,即之前打開的 log 文件。
  4. PS4='($BASH_SOURCE:$LINENO:$FUNCNAME): ':這條命令設置了當 set -x 啟用時,每條命令前面的提示信息格式。$BASH_SOURCE 顯示當前執行腳本的名稱,$LINENO 顯示當前行號,$FUNCNAME 顯示當前函數名。這樣可以讓日誌中的每條命令都帶有易於定位的訊息。
  5. set -x:啟用 shell 的追蹤模式,會將執行的每條命令及其參數打印到 stderr 。在本例中,由於設置了 BASH_XTRACEFD,輸出會被重定向到 file descriptor 111,也就是 log 文件。
  6. ./cih.sh:最後執行名為 cih.sh 的腳本文件。

假設 cih.sh 的內容是產生一個亂數。

#!/bin/bash
function my_func()
{
	var=$RANDOM
}
my_func

那麼執行後的效果如下

$ (exec 111> log ; export SHELLOPTS BASH_XTRACEFD=111 PS4='($BASH_SOURCE:$LINENO:$FUNCNAME): ' ; set -x ; ./cih.sh)

$ cat log
(:1:): ./cih.sh
(./cih.sh:8:): my_func
(./cih.sh:5:my_func): var=21742

老司機的技巧果然不同凡響。