五.shell脚本的跟踪与调试

2019-02-27  本文已影响0人  银鳕鱼小王子

最近在看《鸟哥的LINUX私房菜 基础学习篇》,目前看到了shell脚本这一章,打算在这里简单记录一下这一整章的学习过程和相关的知识点。

参考资料:《鸟哥的LINUX私房菜 基础学习篇》第四版 第十二章
实验环境: Ubuntu18.04

这一小节是shell脚本系列的最后一节内容。在前面的四个小节里,我们学习了编写shell脚本的基本语法,利用之前的知识可以编写复杂的脚本。在实践中,我们常常需要对脚本进行调试,寻找出错的位置和原因。在这一节里,我们学习如何跟踪和调试shell脚本。
在执行脚本前,我们可以直接使用bash的相关参数判断脚本是否有问题。

bash [ -nvx ] scripts.sh
#参数说明:
-n: 不执行脚本,只检查语法错误(没有错误时不显示任何信息)
-v: 在执行前,将脚本的内容显示到屏幕上
-x:将使用到的脚本内容显示在屏幕上
# + 符号后面的内容为脚本内容,通过显示使用到的脚本内容可以方便的知道当前执行到哪一个指令
(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...

到这里,我们已经了解了关于shell脚本的全部内容。下面通过一个实际的脚本,来了解之前的内容都是怎样在实际中被运用的。
下面的脚本来自于github中tf-fater-rcnn-master中的脚本文件,如果是做计算机视觉领域相关领域的同学肯定听说过目标检测网络faster rcnn。为了方便,一些指令的功能已经进行了注释。

#!/bin/bash

#设置bash的输入和输出的环境
set -x  #-x 在命令执行前,会显示命令内容(前面有++符号)
set -e #-e 告诉bash如果任何语句的执行结果不是true则应该退出,防止错误像滚雪球般变大导致一个致命的错误

export PYTHONUNBUFFERED="True"

GPU_ID=$1
DATASET=$2
NET=$3

array=( $@ )#定义数组,数组的元素为执行脚本时输入的参数
len=${#array[@]} #固定用法,获取数组元素的个数
EXTRA_ARGS=${array[@]:3:$len} #取下标为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'`" #'命令' 执行命令相当于$(命令)
exec &> >(tee -a "$LOG")
echo Logging output to "$LOG"

set +x #关闭,与set -x对应
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                                                                                                                                                                            

在这个脚本中可能使用到了一些我们不知道的指令,但是通过查阅相关指令的功能,可以发现整个脚本还是很简单的。我们慢慢的来分析。
首先,#!/bin/bash是第一节内容,脚本的开头指定使用的shell程序。接下的是一些对bash的设置,可以先不管。
然后是GPU_ID=$1 DATASET=$2 NET=$3 这是第二节中关于脚本的默认参数的内容,12...是执行脚本时传入的参数。
接下来又是一堆看不懂的指令,没关系,不影响继续阅读。
我们看接下来的一大段,不就是case...esac条件判断,也是很简单的内容。

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
...

整个脚本看完,是不是感觉还是很简单的?当然,其中的一些没见过的指令还是需要一个个耐心的查阅相关资料,但是整体来说,shell脚本还是很简单而功能强大的。
想要了解更多关于shell脚本的内容?欢迎参考Linux shell脚本 :)

上一篇下一篇

猜你喜欢

热点阅读