成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

10分鐘學會Bash調試

系統 Linux
shell 是用戶和操作系統交互的一個程序,經常用于執行一些自動化或者重復繁瑣的任務,現在所有的 Linux 系統基本都自帶了該程序,我們只需要編寫好shell腳本,直接執行就可以了。

[[411387]]

本文轉載自微信公眾號「Linux開發那些事兒」,作者LinuxThings 。轉載本文請聯系Linux開發那些事兒公眾號。

shell 是用戶和操作系統交互的一個程序,經常用于執行一些自動化或者重復繁瑣的任務,現在所有的 Linux 系統基本都自帶了該程序,我們只需要編寫好shell腳本,直接執行就可以了,不需要額外安裝軟件、配置編譯環境,可以說使用起來非常的方便,但是它在調試方面常常令人頭大,本文主要介紹shell腳本常用的調試方法

調試常用選項

調試shell腳本時,常常用到幾個調試選項,讓腳本在執行的過程中,會輸出一些調試信息,根據調試信息,就可以定位出具體出問題的代碼

具體的選項以及說明如下:

選項 說明
-x 輸出結果之前,先輸出執行的命令
-u 遇到不存在的變量就會報錯,并停止執行
-e 發生錯誤時,終止執行
-n 檢查語法錯誤
-o pipefail 管道子命令發生錯誤,終止執行

跟蹤腳本的執行

  • 輸出調試信息

通常,腳本執行之后,只有結果輸出,當運行多條命令的時候,就會連續輸出多條結果,無法分清哪條命令對應哪條結果, 使用 -x選項,會先輸出將要執行的那一行命令的調試信息,然后再執行命令

現有腳本ta.sh,功能是輸出當前日期, 內容如下

  1. #!/bin/bash 
  2.  
  3. echo "today is :"$(date +'%Y-%m-%d'

我們使用 -x 選項來執行腳本,結果如下

  1. [root@VM-0-2-centos shell_debug]# bash -x ta.sh  
  2. ++ date +%Y-%m-%d 
  3. + echo 'today is :2021-07-10' 
  4. today is :2021-07-10 

從結果中可以看到,在執行前打印出了每一行命令,行前面的 + 號表示調試信息,它實際是環境變量 PS4 的值, PS4 的第一個字符會根據嵌套層次進行重復,命令所處的層次越深,前面的 + 號越多

結果中第一行表示執行 date +'%Y-%m-%d' 命令,它處于第內層,所以打印兩個 + 號 ,第二行表示執行 echo "today is :"$(date +'%Y-%m-%d') 命令,它處于外層,只打印一個 + 號

把 -x 選項放到 #!/bin/bash 語句后面,執行的時候不帶 -x 也能實現同樣的效果,上述腳本只需要把 #!/bin/bash 改成 #!/bin/bash -x 即可

  • 輸出行號

上面示例中腳本內容很少,試想下,如果腳本內容達到了幾百行或者幾千行之后,輸出每一行命令的提示信息,閱讀起來就很費勁了,在這種情況下,我們在每行輸出前加上行號,可以直接定位到具體的行

修改下 ta.sh 腳本,修改后的內容如下

  1. #!/bin/bash  
  2.  
  3. PS4='+${BASH_SOURCE}:${LINENO} ' 
  4. echo "start..." 
  5. set -x 
  6. echo "today is :"$(date +'%Y-%m-%d'
  7. set +x 
  8. echo "end..." 

修改之后的腳本加入了 PS4 變量, 它是調試信息的前綴,默認值是 "+", 我們可以修改它的值,達到輸出的調試信息中包含行號的目的

上述代碼中 "${BASH_SOURCE}" 表示 當前執行的shell腳本的相對路徑,在這里用來表示腳本文件名,"${LINENO}" 表示行號,修改 PS4 之后,輸出的調試信息就會包括 腳本名字以及行號

我們執行腳本,看下結果

  1. [root@VM-0-2-centos shell_debug]# bash -x ta.sh  
  2. + PS4='+${BASH_SOURCE}:${LINENO} ' 
  3. +ta.sh:4 echo start... 
  4. start... 
  5. ++ta.sh:5 date +%Y-%m-%d 
  6. +ta.sh:5 echo 'today is :2021-07-10' 
  7. today is :2021-07-10 
  8. +ta.sh:6 echo end... 
  9. end... 

從結果可以看出,每一行命令的調試信息中都包含了文件名和行號

  • 輸出部分調試信息

有時,我們只需要輸出部分調試信息,這個時候就需要我們手動去設置 -x 選項了,把需要輸出調試信息的命令放到 set -x 和set +x 之間

修改下 ta.sh 腳本,內容如下

  1. #!/bin/bash 
  2.  
  3. echo "test..." 
  4.  
  5. set -x 
  6. echo "today is :"$(date +'%Y-%m-%d'
  7. set +x 
  8.  
  9. echo "finish..." 

執行腳本,結果如下

  1. [root@VM-0-2-centos shell_debug]# ./ta.sh  
  2. [root@VM-0-2-centos shell_debug]# ./ta.sh  
  3. test... 
  4. ++ date +%Y-%m-%d 
  5. + echo 'today is :2021-07-10' 
  6. today is :2021-07-10 
  7. set +x 
  8. finish... 

從結果可以看出,只有 echo today is :"$(date +'%Y-%m-%d') 命令輸出了調試信息,set -x 相當于開啟調試信息,set +x 則是關閉調試信息

這里需要注意下,腳本中使用了 set -x 時 , 執行的時候就不要再加 -x 了

日志打印

通過打印日志來調試shell腳本是常用的方式,在一行命令前后打印變量值或者命令結果,通過日志來判斷是否有錯誤

但是,當腳本比較長的時候,需要打印的日志就有點兒多了,而且,調試完了后,這些調試日志就不再需要了,這時就要一行行的刪掉日志打印

下面介紹一種方法,把腳本中所有的日志打印加一個開關,當開關打開的時候,就會輸出調試相關的日志,不需要的時候,直接關閉開關即可

現有腳本 debug1.sh, 內容如下

  1. #!/bin/bash 
  2.  
  3. #調試開關, on 表示開啟,其他表示關閉 
  4. IS_DEBUG="on" 
  5. #調試開關函數 
  6. function _DEBUG() 
  7.    [ "$IS_DEBUG" == "on" ] && $@ 
  8.  
  9. va=1 
  10. _DEBUG echo 'old value:'$va 
  11. #變量val加1 
  12. let va++ 
  13. echo 'new value:'$va 

上述腳本中,IS_DEBUG變量是調試開關,"on" 表示開啟,其他表示關閉

_DEBUG() 是調試開關函數,它的功能是:如果 IS_DEBUG 為 "on" ,執行后面的命令,否則忽略

先打開調試開關, 執行腳本,結果如下

  1. [root@VM-0-2-centos shell_debug]# ./debug1.sh  
  2. old value:1 
  3. new value:2 

再關閉調試開關,執行腳本,結果如下

  1. [root@VM-0-2-centos shell_debug]# ./debug1.sh  
  2. new value:2 

從上面兩組測試結果可以看出,當打開調試開關,也即設置 IS_DEBUG="on" 后, 語句 _DEBUG echo 'old value:'$va 會執行 echo 'old value:'$va 命令,當 IS_DEBUG="off" 時, 就會忽略 echo 'old value:'$va 命令

所以,當調試的時候,打開調試開關,調試完成之后,腳本不需要做任何修改,只需要關閉開關,調試相關的命令就都不會執行了

常見的錯誤處理

  • 不存在的變量

執行腳本的時候,遇到不存在的變量,默認會忽略它

現有腳本 td.sh, 內容如下

  1. #!/bin/bash 
  2.  
  3.  
  4. echo "start..." 
  5. echo $ta 
  6. echo "end..." 

腳本中 ta 是一個不存在的變量,腳本執行結果如下

  1. [root@VM-0-2-centos shell_debug]# ./td.sh  
  2. start... 
  3.  
  4. end... 

可以看到,echo $ta 輸出了一個空行,腳本直接忽略了不存在的 ta 變量, 并且繼續執行后面的命令

這種情況通常并不是我們希望的結果,遇到不存在的變量,應該直接報錯,并停止執行后面的命令,在腳本開頭加上 set -u 語句或者執行腳本的時候加上 -u ,可以得到我們期望的結果

在腳本開頭加上 set -u 語句,整個腳本內容如下

  1. #!/bin/bash 
  2.  
  3. set -u 
  4. echo "start..." 
  5. echo $ta 
  6. echo "end..." 

執行腳本,結果如下

  1. [root@VM-0-2-centos shell_debug]# ./td.sh  
  2. start... 
  3. ./td.sh: line 5: ta: unbound variable 

可以看到,加了 set -u 語句之后,遇到不存在的變量 ta, 直接報錯,并且停止執行后面的命令

當然,我們使用 bash -u td.sh 命令執行腳本也會得到相同的結果

  • 語法錯誤

語法錯誤是shell腳本執行錯誤的原因之一,執行腳本的時候加上 -n, 當腳本有語法錯誤,不會繼續執行,而是打印錯誤信息

現有腳本 te.sh, 內容如下

  1. #!/bin/bash 
  2.  
  3. if [ $# -le 0 ];then 
  4.    echo "no param.." 

輸入 bash -n te.sh 命令,并回車,結果如下

  1. [root@VM-0-2-centos shell_debug]# bash -n te.sh  
  2. te.sh: line 5: syntax error: unexpected end of file 

上面的腳本中的 if 缺少結尾的 fi, 所以執行 bash -n te.sh 命令之后會出現語法錯誤的提示

這個選項很實用,特別是當我們寫完shell腳本之后,不要急著執行,先使用 -n 選項檢查下有沒有語法錯誤,它可以幫我們提前發現錯誤

  • 發生錯誤,終止執行

一般情況下,腳本執行時發生錯誤了,還是會繼續執行后面的命令

現有腳本 tf.sh, 內容如下

  1. #!/bin/bash 
  2.  
  3. echo "start..." 
  4. abc 
  5. echo "end..." 

執行腳本,結果如下

  1. [root@VM-0-2-centos shell_debug]# ./tf.sh  
  2. start... 
  3. ./tf.sh: line 4: abc: command not found 
  4. end... 

從結果可以看到,腳本中第四行的 abc 是未知的命令,執行時發生了錯誤,但是腳本還是繼續向后執行,一直到結束

這種行為不利于腳本的安全和錯誤排查,在實際應用中,發生了錯誤應該停止執行腳本,防止錯誤越積越多,我們可以使用 -e 選項來避免這個問題

加上 -e 選項,再次執行上述腳本,結果如下

  1. [root@VM-0-2-centos shell_debug]# bash -e ./tf.sh  
  2. start... 
  3. ./tf.sh: line 4: abc: command not found 

從上面結果可以知道,腳本執行到第四行的時候發生了錯誤,此時腳本停止往下執行了

  • 管道子命令失敗,終止執行

上面提到的 -e 選項有個特殊的情況,不適用于管道命令,管道命令是通過管道符 "|" 組合的命令, 具體的看下面的例子吧

現有腳本 tg.sh, 內容如下

  1. #!/bin/bash 
  2.  
  3. echo "start..." 
  4. abc | echo "111" 
  5. echo "end..." 

腳本的第四行, abc | echo "111" 是管道命令,我們執行 bash -e ./tg.sh 命令后,結果如下

  1. [root@VM-0-2-centos shell_debug]# bash -e ./tg.sh  
  2. start... 
  3. ./tg.sh: line 4: abc: command not found 
  4. 111 
  5. end... 

可以看到,即使使用 -e 選項執行腳本,發生錯誤的時候,還是會繼續往下執行,直到結束

我們使用 set -o pipefail 來解決這種情況,只要管道命令中一個子命令發生了錯誤,整個管道命令就失敗了,腳本就會終止執行

修改下上述腳本,內容如下

  1. #!/bin/bash 
  2.  
  3. set -o pipefail 
  4. echo "start..." 
  5. abc | echo "111" 
  6. echo "end..." 

再次執行腳本,結果如下

  1. [root@VM-0-2-centos shell_debug]# bash -e tg.sh  
  2. start... 
  3. tg.sh: line 5: abc: command not found 
  4. 111 

可以看到,在 tg.sh 腳本開頭加上 set -o pipefail 語句之后,再次執行腳本, 管道命令 abc | echo "111" 執行子命令 abc 時發生錯誤,后續的子命令不再執行了,整個管道命令失敗了

 

由于執行時加了 -e 選項,當管道命令執行失敗了,腳本就會終止執行,所以 echo "end..." 沒有執行

 

責任編輯:武曉燕 來源: Linux開發那些事兒
相關推薦

2018-11-28 11:20:53

Python函數式編程編程語言

2019-07-18 16:32:06

Python函數數據

2018-02-01 14:15:00

Python函數

2022-03-08 08:39:22

gRPC協議云原生

2014-04-22 09:42:12

Bash腳本教程

2020-05-22 10:20:27

Shiro架構字符串

2015-03-12 17:01:33

MySQLMySQL亂碼編碼轉換

2018-08-30 09:01:28

Web服務器Windows 10

2016-12-22 21:47:04

SEDLinuxUnix

2018-04-24 14:52:48

LinuxBash腳本

2009-11-05 14:53:54

Visual Stud

2013-09-13 14:08:01

2017-09-27 11:00:50

LinuxBash使用技巧

2009-10-21 18:19:36

VB.NET實現拖放

2009-11-12 16:25:35

Oracle嵌套循環

2021-04-23 09:50:41

topLinux命令

2020-10-13 18:22:58

DevOps工具開發

2014-08-08 09:30:04

android scrollview

2019-11-11 21:24:42

HadoopHbase分布式

2024-07-10 18:55:09

Python定時
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 在线观看国产三级 | 国产视频欧美 | 久久久久国产 | 欧洲精品久久久久毛片完整版 | 国产1区| 国产精品久久久久久久久免费丝袜 | 午夜一区二区三区视频 | 久久婷婷麻豆国产91天堂 | 在线观看国产www | 放个毛片看看 | 国产福利在线播放麻豆 | 国产精品久久久久久福利一牛影视 | 成人av网站在线观看 | 91久久国产综合久久 | 日韩一区二区免费视频 | 亚洲精品国产综合区久久久久久久 | 午夜精品网站 | 精精国产xxxx视频在线 | 毛片网在线观看 | 欧美日韩在线不卡 | a天堂在线 | 小川阿佐美pgd-606在线 | 日韩在线视频一区 | 一级黄色片一级黄色片 | 成人av播放 | www.五月天婷婷 | 久久久久www| 嫩草视频在线看 | 欧美一区二区三区在线播放 | 国产精品亚洲一区 | 性做久久久久久免费观看欧美 | 久久精品一区 | 精品久 | 美女一级a毛片免费观看97 | 最新国产视频 | 青青激情网 | 亚洲国产精品日韩av不卡在线 | 伊人免费在线观看 | 久久久久久久久久久久久9999 | 亚洲一区二区三区四区五区午夜 | 喷潮网站 |