美文网首页
五.shell脚本的跟踪与调试

五.shell脚本的跟踪与调试

作者: 银鳕鱼小王子 | 来源:发表于2019-02-27 21:20 被阅读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。为了方便,一些指令的功能已经进行了注释。

    • 示例:test_faster_rcnn.sh
    #!/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脚本 :)

    相关文章

      网友评论

          本文标题:五.shell脚本的跟踪与调试

          本文链接:https://www.haomeiwen.com/subject/lqkquqtx.html