閱讀856 返回首頁    go 阿裏雲 go 技術社區[雲棲]


如何在 Shell 腳本中跟蹤調試命令的執行

在 shell 腳本調試係列 中,本文將解釋第三種 shell 腳本調試模式,即 shell 跟蹤,並查看一些示例來演示它如何工作以及如何使用它。

本係列的前麵部分清晰地闡明了另外兩種 shell 腳本調試模式:詳細模式和語法檢查模式,並用易於理解的例子展示了如何在這些模式下啟用 shell 腳本調試。

  1. 如何在 Linux 中啟用 Shell 腳本的調試模式
  2. 如何在 Shell 腳本中執行語法檢查調試模式

shell 跟蹤簡單的來說就是跟蹤 shell 腳本中的命令的執行。要打開 shell 跟蹤,請使用 -x 調試選項。

這會讓 shell 在終端上顯示所有執行的命令及其參數。

我們將使用下麵的 sys_info.sh shell 腳本,它會簡要地打印出你的係統日期和時間、登錄的用戶數和係統的運行時間。不過,腳本中包含我們需要查找和更正的語法錯誤。


  1. #!/bin/bash
  2. # script to print brief system info
  3. ROOT_ID="0"
  4. DATE=`date`
  5. NO_USERS=`who | wc -l`
  6. UPTIME=`uptime`
  7. check_root(){
  8. if [ "$UID" -ne "$ROOT_ID" ]; then
  9. echo "You are not allowed to execute this program!"
  10. exit 1;
  11. }
  12. print_sys_info(){
  13. echo "System Time : $DATE"
  14. echo "Number of users: $NO_USERS"
  15. echo "System Uptime : $UPTIME
  16. }
  17. check_root
  18. print_sys_info
  19. exit 0

保存文件並執行腳本。腳本隻能用 root 用戶運行,因此如下使用 sudo 命令運行:


  1. $ chmod +x sys_info.sh
  2. $ sudo bash -x sys_info.sh

shell 跟蹤 - 顯示腳本中的錯誤

shell 跟蹤 - 顯示腳本中的錯誤

從上麵的輸出我們可以觀察到,首先執行命令,然後其輸出做為一個變量的值。

例如,先執行 date,其輸出做為變量 DATE 的值。

我們可以執行語法檢查來隻顯示其中的語法錯誤,如下所示:


  1. $ sudo bash -n sys_info.sh

腳本中語法檢查

腳本中語法檢查

如果我們審視這個 shell 腳本,我們就會發現 if 語句缺少了封閉條件的 fi 關鍵字。因此,讓我們加上它,新的腳本應該看起來像這樣:


  1. #!/bin/bash
  2. #script to print brief system info
  3. ROOT_ID="0"
  4. DATE=`date`
  5. NO_USERS=`who | wc -l`
  6. UPTIME=`uptime`
  7. check_root(){
  8. if [ "$UID" -ne "$ROOT_ID" ]; then
  9. echo "You are not allowed to execute this program!"
  10. exit 1;
  11. fi
  12. }
  13. print_sys_info(){
  14. echo "System Time : $DATE"
  15. echo "Number of users: $NO_USERS"
  16. echo "System Uptime : $UPTIME
  17. }
  18. check_root
  19. print_sys_info
  20. exit 0

再次保存文件並以 root 執行,同時做語法檢查:


  1. $ sudo bash -n sys_info.sh

在 shell 腳本中執行語法檢查

在 shell 腳本中執行語法檢查

上麵的語法檢查操作的結果仍然顯示在腳本的第 21 行還有一個錯誤。所以,我們仍然要糾正一些語法。

再一次分析腳本,會發現第 21 行的錯誤是由於在 print_sys_info 函數內最後一個 echo 命令中沒有閉合雙引號 "

我們將在 echo 命令中添加閉合雙引號並保存文件。修改過的腳本如下:


  1. #!/bin/bash
  2. #script to print brief system info
  3. ROOT_ID="0"
  4. DATE=`date`
  5. NO_USERS=`who | wc -l`
  6. UPTIME=`uptime`
  7. check_root(){
  8. if [ "$UID" -ne "$ROOT_ID" ]; then
  9. echo "You are not allowed to execute this program!"
  10. exit 1;
  11. fi
  12. }
  13. print_sys_info(){
  14. echo "System Time : $DATE"
  15. echo "Number of users: $NO_USERS"
  16. echo "System Uptime : $UPTIME"
  17. }
  18. check_root
  19. print_sys_info
  20. exit 0

現在再一次檢查語法。


  1. $ sudo bash -n sys_info.sh

上麵的命令不會產生任何輸出,因為我們的腳本語法上正確。我們也可以再次跟蹤腳本執行,它應該工作得很好:


  1. $ sudo bash -x sys_info.sh

跟蹤 shell 腳本執行

跟蹤 shell 腳本執行

現在運行腳本。


  1. $ sudo ./sys_info.sh

用 shell 腳本顯示日期、時間和運行時間

用 shell 腳本顯示日期、時間和運行時間

shell 跟蹤執行的重要性

shell 腳本跟蹤可以幫助我們識別語法錯誤,更重要的是識別邏輯錯誤。例如,在 sys_info.sh shell 腳本中的 check_root 函數,它用於確定用戶是否為 root,因為腳本隻允許由超級用戶執行。


  1. check_root(){
  2. if [ "$UID" -ne "$ROOT_ID" ]; then
  3. echo "You are not allowed to execute this program!"
  4. exit 1;
  5. fi
  6. }

這裏的魔法是由 if 語句表達式 ["$ UID" -ne "$ ROOT_ID"] 控製的,一旦我們不使用合適的數字運算符(示例中為 -ne,這意味著不相等),我們最終可能會出一個邏輯錯誤。

假設我們使用 -eq (意思是等於),這將允許任何係統用戶以及 root 用戶運行腳本,因此是一個邏輯錯誤。


  1. check_root(){
  2. if [ "$UID" -eq "$ROOT_ID" ]; then
  3. echo "You are not allowed to execute this program!"
  4. exit 1;
  5. fi
  6. }

注意:我們在本係列開頭介紹過,set 這個 shell 內置命令可以在 shell 腳本的特定部分激活調試。

因此,下麵的行將幫助我們通過跟蹤腳本的執行在其中找到這個邏輯錯誤:

具有邏輯錯誤的腳本:


  1. #!/bin/bash
  2. #script to print brief system info
  3. ROOT_ID="0"
  4. DATE=`date`
  5. NO_USERS=`who | wc -l`
  6. UPTIME=`uptime`
  7. check_root(){
  8. if [ "$UID" -eq "$ROOT_ID" ]; then
  9. echo "You are not allowed to execute this program!"
  10. exit 1;
  11. fi
  12. }
  13. print_sys_info(){
  14. echo "System Time : $DATE"
  15. echo "Number of users: $NO_USERS"
  16. echo "System Uptime : $UPTIME"
  17. }
  18. #turning on and off debugging of check_root function
  19. set -x ; check_root; set +x ;
  20. print_sys_info
  21. exit 0

保存文件並調用腳本,在輸出中,我們可以看到一個普通係統用戶可以在未 sudo 的情況下運行腳本。 這是因為 USER_ID 的值為 100,不等於為 0 的 root 的 ROOT_ID 。


  1. $ ./sys_info.sh

Run Shell Script Without Sudo

Run Shell Script Without Sudo

原文發布時間為:2017-01-15

本文來自雲棲社區合作夥伴“Linux中國”

最後更新:2017-05-27 10:32:47

  上一篇:go  你值得了解的 10 個有趣的 Linux 命令行小技巧
  下一篇:go  Google、百度年終盤點出爐,全球網民都在搜索什麼?