如何在 Shell 腳本中跟蹤調試命令的執行
本系列的前面部分清晰地闡明了另外兩種 shell 腳本調試模式:詳細模式和語法檢查模式,並用易於理解的例子展示了如何在這些模式下啟用 shell 腳本調試。
shell 跟蹤簡單的來說就是跟蹤 shell 腳本中的命令的執行。要打開 shell 跟蹤,請使用 -x
調試選項。
這會讓 shell 在終端上顯示所有執行的命令及其參數。
我們將使用下面的 sys_info.sh
shell 腳本,它會簡要地列印出你的系統日期和時間、登錄的用戶數和系統的運行時間。不過,腳本中包含我們需要查找和更正的語法錯誤。
#!/bin/bash
# script to print brief system info
ROOT_ID="0"
DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`
check_root(){
if [ "$UID" -ne "$ROOT_ID" ]; then
echo "You are not allowed to execute this program!"
exit 1;
}
print_sys_info(){
echo "System Time : $DATE"
echo "Number of users: $NO_USERS"
echo "System Uptime : $UPTIME
}
check_root
print_sys_info
exit 0
保存文件並執行腳本。腳本只能用 root 用戶運行,因此如下使用 sudo 命令運行:
$ chmod +x sys_info.sh
$ sudo bash -x sys_info.sh
shell 跟蹤 - 顯示腳本中的錯誤
從上面的輸出我們可以觀察到,首先執行命令,然後其輸出做為一個變數的值。
例如,先執行 date
,其輸出做為變數 DATE
的值。
我們可以執行語法檢查來只顯示其中的語法錯誤,如下所示:
$ sudo bash -n sys_info.sh
腳本中語法檢查
如果我們審視這個 shell 腳本,我們就會發現 if
語句缺少了封閉條件的 fi
關鍵字。因此,讓我們加上它,新的腳本應該看起來像這樣:
#!/bin/bash
#script to print brief system info
ROOT_ID="0"
DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`
check_root(){
if [ "$UID" -ne "$ROOT_ID" ]; then
echo "You are not allowed to execute this program!"
exit 1;
fi
}
print_sys_info(){
echo "System Time : $DATE"
echo "Number of users: $NO_USERS"
echo "System Uptime : $UPTIME
}
check_root
print_sys_info
exit 0
再次保存文件並以 root 執行,同時做語法檢查:
$ sudo bash -n sys_info.sh
在 shell 腳本中執行語法檢查
上面的語法檢查操作的結果仍然顯示在腳本的第 21 行還有一個錯誤。所以,我們仍然要糾正一些語法。
再一次分析腳本,會發現第 21 行的錯誤是由於在 print_sys_info
函數內最後一個 echo 命令中沒有閉合雙引號 "
。
我們將在 echo
命令中添加閉合雙引號並保存文件。修改過的腳本如下:
#!/bin/bash
#script to print brief system info
ROOT_ID="0"
DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`
check_root(){
if [ "$UID" -ne "$ROOT_ID" ]; then
echo "You are not allowed to execute this program!"
exit 1;
fi
}
print_sys_info(){
echo "System Time : $DATE"
echo "Number of users: $NO_USERS"
echo "System Uptime : $UPTIME"
}
check_root
print_sys_info
exit 0
現在再一次檢查語法。
$ sudo bash -n sys_info.sh
上面的命令不會產生任何輸出,因為我們的腳本語法上正確。我們也可以再次跟蹤腳本執行,它應該工作得很好:
$ sudo bash -x sys_info.sh
跟蹤 shell 腳本執行
現在運行腳本。
$ sudo ./sys_info.sh
用 shell 腳本顯示日期、時間和運行時間
shell 跟蹤執行的重要性
shell 腳本跟蹤可以幫助我們識別語法錯誤,更重要的是識別邏輯錯誤。例如,在 sys_info.sh
shell 腳本中的 check_root
函數,它用於確定用戶是否為 root,因為腳本只允許由超級用戶執行。
check_root(){
if [ "$UID" -ne "$ROOT_ID" ]; then
echo "You are not allowed to execute this program!"
exit 1;
fi
}
這裡的魔法是由 if
語句表達式 ["$ UID" -ne "$ ROOT_ID"]
控制的,一旦我們不使用合適的數字運算符(示例中為 -ne
,這意味著不相等),我們最終可能會出一個邏輯錯誤。
假設我們使用 -eq
(意思是等於),這將允許任何系統用戶以及 root 用戶運行腳本,因此是一個邏輯錯誤。
check_root(){
if [ "$UID" -eq "$ROOT_ID" ]; then
echo "You are not allowed to execute this program!"
exit 1;
fi
}
注意:我們在本系列開頭介紹過,set
這個 shell 內置命令可以在 shell 腳本的特定部分激活調試。
因此,下面的行將幫助我們通過跟蹤腳本的執行在其中找到這個邏輯錯誤:
具有邏輯錯誤的腳本:
#!/bin/bash
#script to print brief system info
ROOT_ID="0"
DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`
check_root(){
if [ "$UID" -eq "$ROOT_ID" ]; then
echo "You are not allowed to execute this program!"
exit 1;
fi
}
print_sys_info(){
echo "System Time : $DATE"
echo "Number of users: $NO_USERS"
echo "System Uptime : $UPTIME"
}
#turning on and off debugging of check_root function
set -x ; check_root; set +x ;
print_sys_info
exit 0
保存文件並調用腳本,在輸出中,我們可以看到一個普通系統用戶可以在未 sudo 的情況下運行腳本。 這是因為 USER_ID
的值為 100,不等於為 0 的 root 的 ROOT_ID
。
$ ./sys_info.sh
未 sudo 的情況下運行 shell 腳本
那麼,現在我們已經完成了 shell 腳本調試系列,可以在下面的反饋欄里給我們關於本篇或者本系列提出問題或反饋。
作者簡介:
Aaron Kili 是 Linux 和 F.O.S.S 愛好者,將來的 Linux SysAdmin、web 開 發人員,目前是 TecMint 的內容創作者,他喜歡用電腦工作,並堅信分享知識。
via: http://www.tecmint.com/trace-shell-script-execution-in-linux/
作者:Aaron Kili 譯者:geekpi 校對:jasminepeng
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive