腳本除錯(cuò)

腳本除錯(cuò)

本章介紹如何對 Shell 腳本除錯(cuò)麻汰。

常見錯(cuò)誤

編寫 Shell 腳本的時(shí)候速客,一定要考慮到命令失敗的情況,否則很容易出錯(cuò)五鲫。

#! /bin/bash

dir_name=/path/not/exist

cd $dir_name
rm *

上面腳本中溺职,如果目錄$dir_name不存在,cd $dir_name命令就會執(zhí)行失敗。這時(shí)浪耘,就不會改變當(dāng)前目錄智亮,腳本會繼續(xù)執(zhí)行下去,導(dǎo)致rm *命令刪光當(dāng)前目錄的文件点待。

如果改成下面的樣子阔蛉,也會有問題。

cd $dir_name && rm *

上面腳本中癞埠,只有cd $dir_name執(zhí)行成功状原,才會執(zhí)行rm *。但是苗踪,如果變量$dir_name為空颠区,cd就會進(jìn)入用戶主目錄,從而刪光用戶主目錄的文件通铲。

下面的寫法才是正確的毕莱。

[[ -d $dir_name ]] && cd $dir_name && rm *

上面代碼中,先判斷目錄$dir_name是否存在颅夺,然后才執(zhí)行其他操作朋截。

如果不放心刪除什么文件,可以先打印出來看一下吧黄。

[[ -d $dir_name ]] && cd $dir_name && echo rm *

上面命令中部服,echo rm *不會刪除文件,只會打印出來要?jiǎng)h除的文件拗慨。

bash-x參數(shù)

bash-x參數(shù)可以在執(zhí)行每一行命令之前廓八,打印該命令。一旦出錯(cuò)赵抢,這樣就比較容易追查剧蹂。

下面是一個(gè)腳本script.sh

# script.sh
echo hello world

加上-x參數(shù)烦却,執(zhí)行每條命令之前宠叼,都會顯示該命令。

$ bash -x script.sh
+ echo hello world
hello world

上面例子中短绸,行首為+的行车吹,顯示該行是所要執(zhí)行的命令,下一行才是該命令的執(zhí)行結(jié)果醋闭。

下面再看一個(gè)-x寫在腳本內(nèi)部的例子窄驹。

#! /bin/bash -x
# trouble: script to demonstrate common errors

number=1
if [ $number = 1 ]; then
  echo "Number is equal to 1."
else
  echo "Number is not equal to 1."
fi

上面的腳本執(zhí)行之后,會輸出每一行命令证逻。

$ trouble
+ number=1
+ '[' 1 = 1 ']'
+ echo 'Number is equal to 1.'
Number is equal to 1.

輸出的命令之前的+號乐埠,是由系統(tǒng)變量PS4決定,可以修改這個(gè)變量。

$ export PS4='$LINENO + '
$ trouble
5 + number=1
7 + '[' 1 = 1 ']'
8 + echo 'Number is equal to 1.'
Number is equal to 1.

另外丈咐,set命令也可以設(shè)置 Shell 的行為參數(shù)瑞眼,有利于腳本除錯(cuò),詳見《set 命令》一章棵逊。

環(huán)境變量

有一些環(huán)境變量常用于除錯(cuò)伤疙。

LINENO

變量LINENO返回它在腳本里面的行號。

#!/bin/bash

echo "This is line $LINENO"

執(zhí)行上面的腳本test.sh辆影,$LINENO會返回3徒像。

$ ./test.sh
This is line 3

FUNCNAME

變量FUNCNAME返回一個(gè)數(shù)組,內(nèi)容是當(dāng)前的函數(shù)調(diào)用堆棧蛙讥。該數(shù)組的0號成員是當(dāng)前調(diào)用的函數(shù)锯蛀,1號成員是調(diào)用當(dāng)前函數(shù)的函數(shù),以此類推次慢。

#!/bin/bash

function func1()
{
  echo "func1: FUNCNAME0 is ${FUNCNAME[0]}"
  echo "func1: FUNCNAME1 is ${FUNCNAME[1]}"
  echo "func1: FUNCNAME2 is ${FUNCNAME[2]}"
  func2
}

function func2()
{
  echo "func2: FUNCNAME0 is ${FUNCNAME[0]}"
  echo "func2: FUNCNAME1 is ${FUNCNAME[1]}"
  echo "func2: FUNCNAME2 is ${FUNCNAME[2]}"
}

func1

執(zhí)行上面的腳本test.sh旁涤,結(jié)果如下。

$ ./test.sh
func1: FUNCNAME0 is func1
func1: FUNCNAME1 is main
func1: FUNCNAME2 is
func2: FUNCNAME0 is func2
func2: FUNCNAME1 is func1
func2: FUNCNAME2 is main

上面例子中迫像,執(zhí)行func1時(shí)劈愚,變量FUNCNAME的0號成員是func1,1號成員是調(diào)用func1的主腳本main侵蒙。執(zhí)行func2時(shí)造虎,變量FUNCNAME的0號成員是func2,1號成員是調(diào)用func2func1纷闺。

BASH_SOURCE

變量BASH_SOURCE返回一個(gè)數(shù)組,內(nèi)容是當(dāng)前的腳本調(diào)用堆棧份蝴。該數(shù)組的0號成員是當(dāng)前執(zhí)行的腳本犁功,1號成員是調(diào)用當(dāng)前腳本的腳本,以此類推婚夫,跟變量FUNCNAME是一一對應(yīng)關(guān)系浸卦。

下面有兩個(gè)子腳本lib1.shlib2.sh

# lib1.sh
function func1()
{
  echo "func1: BASH_SOURCE0 is ${BASH_SOURCE[0]}"
  echo "func1: BASH_SOURCE1 is ${BASH_SOURCE[1]}"
  echo "func1: BASH_SOURCE2 is ${BASH_SOURCE[2]}"
  func2
}
# lib2.sh
function func2()
{
  echo "func2: BASH_SOURCE0 is ${BASH_SOURCE[0]}"
  echo "func2: BASH_SOURCE1 is ${BASH_SOURCE[1]}"
  echo "func2: BASH_SOURCE2 is ${BASH_SOURCE[2]}"
}

然后案糙,主腳本main.sh調(diào)用上面兩個(gè)子腳本限嫌。

#!/bin/bash
# main.sh

source lib1.sh
source lib2.sh

func1

執(zhí)行主腳本main.sh,會得到下面的結(jié)果时捌。

$ ./main.sh
func1: BASH_SOURCE0 is lib1.sh
func1: BASH_SOURCE1 is ./main.sh
func1: BASH_SOURCE2 is
func2: BASH_SOURCE0 is lib2.sh
func2: BASH_SOURCE1 is lib1.sh
func2: BASH_SOURCE2 is ./main.sh

上面例子中怒医,執(zhí)行函數(shù)func1時(shí),變量BASH_SOURCE的0號成員是func1所在的腳本lib1.sh奢讨,1號成員是主腳本main.sh稚叹;執(zhí)行函數(shù)func2時(shí),變量BASH_SOURCE的0號成員是func2所在的腳本lib2.sh,1號成員是調(diào)用func2的腳本lib1.sh扒袖。

BASH_LINENO

變量BASH_LINENO返回一個(gè)數(shù)組塞茅,內(nèi)容是每一輪調(diào)用對應(yīng)的行號。${BASH_LINENO[$i]}${FUNCNAME[$i]}是一一對應(yīng)關(guān)系季率,表示${FUNCNAME[$i]}在調(diào)用它的腳本文件${BASH_SOURCE[$i+1]}里面的行號野瘦。

下面有兩個(gè)子腳本lib1.shlib2.sh

# lib1.sh
function func1()
{
  echo "func1: BASH_LINENO is ${BASH_LINENO[0]}"
  echo "func1: FUNCNAME is ${FUNCNAME[0]}"
  echo "func1: BASH_SOURCE is ${BASH_SOURCE[1]}"

  func2
}
# lib2.sh
function func2()
{
  echo "func2: BASH_LINENO is ${BASH_LINENO[0]}"
  echo "func2: FUNCNAME is ${FUNCNAME[0]}"
  echo "func2: BASH_SOURCE is ${BASH_SOURCE[1]}"
}

然后飒泻,主腳本main.sh調(diào)用上面兩個(gè)子腳本缅刽。

#!/bin/bash
# main.sh

source lib1.sh
source lib2.sh

func1

執(zhí)行主腳本main.sh,會得到下面的結(jié)果蠢络。

$ ./main.sh
func1: BASH_LINENO is 7
func1: FUNCNAME is func1
func1: BASH_SOURCE is main.sh
func2: BASH_LINENO is 8
func2: FUNCNAME is func2
func2: BASH_SOURCE is lib1.sh

上面例子中衰猛,函數(shù)func1是在main.sh的第7行調(diào)用,函數(shù)func2是在lib1.sh的第8行調(diào)用的刹孔。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啡省,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子髓霞,更是在濱河造成了極大的恐慌卦睹,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件方库,死亡現(xiàn)場離奇詭異结序,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)纵潦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門徐鹤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人邀层,你說我怎么就攤上這事返敬。” “怎么了寥院?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵劲赠,是天一觀的道長。 經(jīng)常有香客問我秸谢,道長凛澎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任估蹄,我火速辦了婚禮塑煎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘元媚。我一直安慰自己轧叽,他們只是感情好苗沧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著炭晒,像睡著了一般待逞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上网严,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天识樱,我揣著相機(jī)與錄音,去河邊找鬼震束。 笑死芹啥,一個(gè)胖子當(dāng)著我的面吹牛瞬测,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼碴犬,長吁一口氣:“原來是場噩夢啊……” “哼狰域!你這毒婦竟也來了碍讨?” 一聲冷哼從身側(cè)響起捐祠,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侵佃,沒想到半個(gè)月后麻昼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馋辈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年抚芦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片迈螟。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叉抡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出井联,到底是詐尸還是另有隱情卜壕,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布烙常,位于F島的核電站,受9級特大地震影響鹤盒,放射性物質(zhì)發(fā)生泄漏蚕脏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一侦锯、第九天 我趴在偏房一處隱蔽的房頂上張望驼鞭。 院中可真熱鬧,春花似錦尺碰、人聲如沸挣棕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽洛心。三九已至固耘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間词身,已是汗流浹背厅目。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留法严,地道東北人损敷。 一個(gè)月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像深啤,于是被迫代替她去往敵國和親拗馒。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容