shell编程 - 故障诊断

        随着脚本的复杂度越来越高,当脚本出现错误或者执行情况与预期不同的时候,需要看是哪里出现问题。本节介绍常见的错误类型以及追踪和解除错误的有用技巧。

语法错误

语法错误是常见的一种错误类型。大多数情况,shell会拒绝执行此类错误类型的脚本。

#!/bin/bash

# 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

 常见的语法错误类型包括

引号缺失

#!/bin/bash

# trouble:script to demonstrate common errors

number=1

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

以上脚本第一个echo语句中的实参缺少闭合引号。

符号缺失

#!/bin/bash

# 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

 if命令中test后缺失分号;,导致破坏了if的语法结构,会提示相应的错误。

非预期的扩展

#!/bin/bash

# trouble:script to demonstrate common errors

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

 expansion扩展number变量为空,就造成了 [  = 1 ],该等式无效,也就产生了错误。

用户可以通过在test命令中使用双引号引用第一个参数方式来更正这个错误。

[ "$number" = 1 ] 扩展变量展开为 [ "" = 1 ]。

除了空字符串需要引用外,类似包含空格的文件名这样的多字符的字符串也要前后加以引号。

逻辑错误

        与语法错误不同的是,逻辑错误不会影响脚本的执行,但执行结果与预期的结果可能存在差异。可能发生的逻辑错误有很多种。比如条件表达式错误、“从1开始”错误、非预期的情形。

防御编程

在编程中核实各种假设是很重要的事情。

cd $dir_name
rm *

 以上如果dir_name变量目录不存在,cd命令跳转失败,脚本会继续读取执行下一行代码,删除的就是当前的工作目录所有内容。修改如下

cd $dir_name && rm *

 这样的话,如果跳转失败,就不会执行删除动作。情况有所改善,但是如果dir_name为空的情况下,cd 空 会跳转至用户的主目录,也就存在用户的主目录被全部删除的可能性。为了进一步改进,检查dir_name是否有效存在就可以避免此情形

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

 通常来说,若发生了上述情形之一,我们需要退出脚本的执行

if [[ -d $dir_name ]];then
    if cd $dir_name;then
        rm *
    else
        echo "cannot cd to '$dir_name'" >&2
        exit 1
    fi
else
    echo "No such directory:'$dir_name'" >&2
    exit 1
fi

以上代码,不仅检查dir_name是否包含有效的目录名,且验证了cd命令是否跳转成功。任一验证没有通过的话,将对应的描述性报错信息发送给系统标准错误,且脚本终止运行,其退出状态为1,标志着运行失败。

输入值验证 

一条普遍适用的编程法则是若程序需获得用户输入,则程序必须能够处理任何输入值。

有时输入值验证类型的测试表达式写起来非常有挑战性,但却是编写高质量脚本的必经之路。

测试

桩(stub)

if [[ -d $dir_name ]];then
    if cd $dir_name;then
        echo rm * # TESTING
    else
        echo "cannot cd to '$dir_name'" >&2
        exit 1
    fi
else
    echo "No such directory:'$dir_name'" >&2
    exit 1
fi
exit # TESTING

 与之前的脚本不一样的点:

        rm命令之前放置了echo命令,使得rm命令和扩展的命令参数可以打印出来,而不是进行实际的删除操作,从而使代码能够安全的执行,进行测试。

        在代码片段的末尾,添加了exit命令用来结束测试,防止执行脚本的其他部分。是否需要添加exit命令取决于不同脚本的不同设计。

        在测试的过程中需要加上标注——注释信息等,来记录做出的改变。方便于测试结束后根据注释信息还原代码。

测试用例

注意分析能够反映出边缘测试的输入数据和操作条件,应用高质量的测试用例。

调试

        如果测试发现脚本存在问题,下一步就需要进行调试操作。调试是一门在实践中成长的艺术。

找到问题域

        在一些长脚本中,将问题相关的部分脚本隔离出来是很有必要的。其中一种能够用于隔离代码片段的方法是注释掉脚本的一部分。

if [[ -d $dir_name ]];then
    if cd $dir_name;then
        rm *
    else
        echo "cannot cd to '$dir_name'" >&2
        exit 1
    fi
# else
#     echo "No such directory:'$dir_name'" >&2
#     exit 1
fi

追踪

        追踪是一种用于查看程序实际运行流程的技术。

        其中,一种方法是通过在脚本中添加打印信息的方式来展示程序执行之处。

echo "preparing to delete files" >&2
if [[ -d $dir_name ]];then
    if cd $dir_name;then
echo "deleting files" >&2
        rm *
    else
        echo "cannot cd to '$dir_name'" >&2
        exit 1
else
    echo "no such directory:'$dir_name'" >&2
    exit 1
fi
echo "file deletion complete" >&2

将添加的打印信息发送给标准错误。这些信息所在行没有进行缩进,使这些代码在需要删除的时候易于寻找。

        bash也提供了一种追踪的方法。即直接使用-x选项或set命令加-x选项。

要对脚本选定的一部分而不是整个脚本执行追踪,可以使用set命令加-x选项。

#!/bin/bash

# trouble:script to demonstrate common errors

number=1

set -x # Turn on tracing
if [ $number = 1 ];then
    echo "Number is equal to 1."
else
    echo "Number is not equal to 1."
fi
set +x # Turn off tracing

 使用set -x激活追踪,set命令加+x解除追踪。这项技术可以用来检验脚本的多个部分。

运行过程中变量的检验

        在执行脚本并追踪脚本执行的过程中,显示各变量的值以体现脚本的内部活动会很有帮助。这项功能通常通过添加额外的echo语句来完成。

#!/bin/bash

# trouble:script to demonstrate common errors

number=1

echo "number=$number" # DEBUG
set -x # Turn on tracing
if [ $number = 1 ];then
    echo "Number is equal to 1."
else
    echo "Number is not equal to 1."
fi
set +x # Turn off tracing

输出变量number的值,并使用注释标注,便于之后的识别和删除。通常适用于带有循环和计算功能的脚本。


可以关注作者微信公众号,追踪更多有价值的内容!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值