最近在看《鳥哥的LINUX私房菜 基礎(chǔ)學(xué)習(xí)篇》潮太,目前看到了shell腳本這一章,打算在這里簡單記錄一下這一整章的學(xué)習(xí)過程和相關(guān)的知識點天通。
參考資料:《鳥哥的LINUX私房菜 基礎(chǔ)學(xué)習(xí)篇》第四版 第十二章
實驗環(huán)境: Ubuntu18.04
這一小節(jié)是shell腳本系列的最后一節(jié)內(nèi)容莫瞬。在前面的四個小節(jié)里,我們學(xué)習(xí)了編寫shell腳本的基本語法搓蚪,利用之前的知識可以編寫復(fù)雜的腳本蛤售。在實踐中,我們常常需要對腳本進(jìn)行調(diào)試妒潭,尋找出錯的位置和原因悴能。在這一節(jié)里,我們學(xué)習(xí)如何跟蹤和調(diào)試shell腳本雳灾。
在執(zhí)行腳本前漠酿,我們可以直接使用bash的相關(guān)參數(shù)判斷腳本是否有問題。
bash [ -nvx ] scripts.sh
#參數(shù)說明:
-n: 不執(zhí)行腳本谎亩,只檢查語法錯誤(沒有錯誤時不顯示任何信息)
-v: 在執(zhí)行前炒嘲,將腳本的內(nèi)容顯示到屏幕上
-x:將使用到的腳本內(nèi)容顯示在屏幕上
- 簡單的示例
# + 符號后面的內(nèi)容為腳本內(nèi)容,通過顯示使用到的腳本內(nèi)容可以方便的知道當(dāng)前執(zhí)行到哪一個指令
(base) laifeng@laifeng-X6:~/bin$ bash -x show_animal.sh
+ for animal in dog cat elephant
+ echo 'There are dogs...'
There are dogs...
+ for animal in dog cat elephant
+ echo 'There are cats...'
There are cats...
+ for animal in dog cat elephant
+ echo 'There are elephants...'
There are elephants...
到這里匈庭,我們已經(jīng)了解了關(guān)于shell腳本的全部內(nèi)容夫凸。下面通過一個實際的腳本,來了解之前的內(nèi)容都是怎樣在實際中被運用的阱持。
下面的腳本來自于github中tf-fater-rcnn-master中的腳本文件夭拌,如果是做計算機(jī)視覺領(lǐng)域相關(guān)領(lǐng)域的同學(xué)肯定聽說過目標(biāo)檢測網(wǎng)絡(luò)faster rcnn。為了方便,一些指令的功能已經(jīng)進(jìn)行了注釋鸽扁。
- 示例:test_faster_rcnn.sh
#!/bin/bash
#設(shè)置bash的輸入和輸出的環(huán)境
set -x #-x 在命令執(zhí)行前道逗,會顯示命令內(nèi)容(前面有++符號)
set -e #-e 告訴bash如果任何語句的執(zhí)行結(jié)果不是true則應(yīng)該退出,防止錯誤像滾雪球般變大導(dǎo)致一個致命的錯誤
export PYTHONUNBUFFERED="True"
GPU_ID=$1
DATASET=$2
NET=$3
array=( $@ )#定義數(shù)組,數(shù)組的元素為執(zhí)行腳本時輸入的參數(shù)
len=${#array[@]} #固定用法献烦,獲取數(shù)組元素的個數(shù)
EXTRA_ARGS=${array[@]:3:$len} #取下標(biāo)為3開始的所有元素
EXTRA_ARGS_SLUG=${EXTRA_ARGS// /_} #變量替換 ${value//pattern/string}將value中與pattern匹配的部分替換成string,這里將 替換成_
#case分支判斷
case ${DATASET} in
pascal_voc)
TRAIN_IMDB="voc_2007_trainval"
TEST_IMDB="voc_2007_test"
ITERS=70000
ANCHORS="[8,16,32]"
RATIOS="[0.5,1,2]"
;;
pascal_voc_0712)
TRAIN_IMDB="voc_2007_trainval+voc_2012_trainval"
TEST_IMDB="voc_2007_test"
ITERS=110000
ANCHORS="[8,16,32]"
RATIOS="[0.5,1,2]"
;;
coco)
TRAIN_IMDB="coco_2014_train+coco_2014_valminusminival"
TEST_IMDB="coco_2014_minival"
ITERS=490000
ANCHORS="[4,8,16,32]"
RATIOS="[0.5,1,2]"
;;
*)
echo "No dataset given"
exit
;;
esac
LOG="experiments/logs/test_${NET}_${TRAIN_IMDB}_${EXTRA_ARGS_SLUG}.txt.`date +'%Y-%m-%d_%H-%M-%S'`" #'命令' 執(zhí)行命令相當(dāng)于$(命令)
exec &> >(tee -a "$LOG")
echo Logging output to "$LOG"
set +x #關(guān)閉滓窍,與set -x對應(yīng)
if [[ ! -z ${EXTRA_ARGS_SLUG} ]]; then #-z 判斷字符串是否為空,為空時返回true巩那;
NET_FINAL=output/${NET}/${TRAIN_IMDB}/${EXTRA_ARGS_SLUG}/${NET}_faster_rcnn_iter_${ITERS}.ckpt
else
NET_FINAL=output/${NET}/${TRAIN_IMDB}/default/${NET}_faster_rcnn_iter_${ITERS}.ckpt
fi
set -x
if [[ ! -z ${EXTRA_ARGS_SLUG} ]]; then
CUDA_VISIBLE_DEVICES=${GPU_ID} time python ./tools/test_net.py \
--imdb ${TEST_IMDB} \
--model ${NET_FINAL} \
--cfg experiments/cfgs/${NET}.yml \
--tag ${EXTRA_ARGS_SLUG} \
--net ${NET} \
--set ANCHOR_SCALES ${ANCHORS} ANCHOR_RATIOS ${RATIOS} \
${EXTRA_ARGS}
else
CUDA_VISIBLE_DEVICES=${GPU_ID} time python ./tools/test_net.py \
--imdb ${TEST_IMDB} \
--model ${NET_FINAL} \
--cfg experiments/cfgs/${NET}.yml \
--net ${NET} \
--set ANCHOR_SCALES ${ANCHORS} ANCHOR_RATIOS ${RATIOS} \
${EXTRA_ARGS}
fi
在這個腳本中可能使用到了一些我們不知道的指令吏夯,但是通過查閱相關(guān)指令的功能,可以發(fā)現(xiàn)整個腳本還是很簡單的即横。我們慢慢的來分析噪生。
首先,#!/bin/bash
是第一節(jié)內(nèi)容东囚,腳本的開頭指定使用的shell程序跺嗽。接下的是一些對bash的設(shè)置,可以先不管页藻。
然后是GPU_ID=$1
DATASET=$2
NET=$3
這是第二節(jié)中關(guān)于腳本的默認(rèn)參數(shù)的內(nèi)容桨嫁,2...是執(zhí)行腳本時傳入的參數(shù)。
接下來又是一堆看不懂的指令份帐,沒關(guān)系璃吧,不影響繼續(xù)閱讀。
我們看接下來的一大段,不就是case...esac條件判斷废境,也是很簡單的內(nèi)容畜挨。
case ${DATASET} in
pascal_voc)
TRAIN_IMDB="voc_2007_trainval"
...
;;
pascal_voc_0712)
TRAIN_IMDB="voc_2007_trainval+voc_2012_trainval"
...
;;
coco)
TRAIN_IMDB="coco_2014_train+coco_2014_valminusminival"
...
;;
*)
echo "No dataset given"
exit
;;
esac
最后的兩大段,就是簡單的if...else..fi條件判斷噩凹。
if [[ ! -z ${EXTRA_ARGS_SLUG} ]]; then #-z 判斷字符串是否為空巴元,為空時返回true;
NET_FINAL=output/${NET}/${TRAIN_IMDB}/${EXTRA_ARGS_SLUG}/${NET}_faster_rcnn_iter_${ITERS}.ckpt
else
NET_FINAL=output/${NET}/${TRAIN_IMDB}/default/${NET}_faster_rcnn_iter_${ITERS}.ckpt
fi
...
整個腳本看完驮宴,是不是感覺還是很簡單的逮刨?當(dāng)然,其中的一些沒見過的指令還是需要一個個耐心的查閱相關(guān)資料幻赚,但是整體來說禀忆,shell腳本還是很簡單而功能強(qiáng)大的。
想要了解更多關(guān)于shell腳本的內(nèi)容落恼?歡迎參考Linux shell腳本 :)