如何在shell中处理异常
2015-08-18 10:14
399 查看
前言
似乎好像大概有句话是这么说得,好程序与坏程序之间的区别就在于它的鲁棒性,也就是在异常情况下该程序是否还是在可hold住状态,能否不死,不崩溃,或者不做出一些超出预期的事情。那要做好这些,自然而然就要学会如何去处理异常。平时写php或者java程序等等的时候,很多人都会去注重对于异常的处理,比如try..catch等等,但往往在写一些脚本的时候,忽视了对于异常的判断。本文主要就是写如何在shell中去处理异常。因为今天太晚了,所以我就先写第一部分,后面再写第二部分。
返回值
要判断一段代码是否出现了异常,一个最基本的判断就是对他返回值的判断。在shell中,我们往往规定0为正常,一切非0返回值则为不正常。但往往我们在写shell脚本的时候,忽略对于返回值的判断。我们看一个很基本的shell程序#!/bin/sh cd /home/xxxx/ rm -rf *
这个脚本的意思很简单,就是cd到某一个目录下,然后将该目录下所有的内容都删除。首先,rm这种东西出现在脚本中,就是一个很危险的操作,而这个程序的关键之处还在于,并没有对第一行shell的返回值进行任何的判断,也就是说对于cd那行代码无论执行失败与否,都会去执行下面的那段rm,试想如果在某些情况下cd那段代码失败了之后,会出现多么可怕的后果。所以,我们应该对于cd的代码做返回值的判断。
#!/bin/sh cd /home/xxxx/ if [ "$?"= "0" ]; then rm -rf * else echo "cannot change directory" 1>&2 exit 1 fi
$?这个常量代表的就是上一段shell的返回值。这个我在前面一片文章里也提到过shell中的trap和expr。这样写的话,就要比先前的程序安全多了,如果没有cd到相应目录,则不会去执行删除操作。
当然,程序里这样写是有些负责了,其实你也可以这样写:
if cd /home/xxxx/ ; then rm -rf * else echo "cannot change directory" 1>&2 exit 1
这是if的另一种用法。这样写,就要比刚才的好多了。不过其实这样写,也比较麻烦,其实你还可以这样来写:
cd /home/xxxx/ && rm -rf *
这个&&符大家肯定不陌生,那这样来写,是否就可以保证了程序的安全性了呢?下面就来讲一下&&和||
&&和||
对于一个shell程序, shell1 && shell2 ,如果是用&&符连接的,那只有在shell1返回0(即正常)时,shell2才会执行,否则shell2根本就不执行,所以前面说得最后一种cd&&rm的这种做法是可行的,而且是安全的。那||呢,对于shell1||shell2,只有在shell1执行失败时,shell2才会执行,否则shell2是不执行得。所以,我们可以这样来写:cd /home/xxxx || error_exit "Cannot change directory" rm -rf *
这样,在cd /home/xxxx失败时,就会进行error_exit这个函数的分支。那error_exit这个是啥函数呢。。哦,其实,这只是一个自定义的失败处理函数而已。一个比较简单的定义,当然,这也是处理程序异常的一个方式。因为总不能每次异常,都去手动写个echo failed exit等等,所以有个统一的函数处理会比较方便。
function error_exit { echo "$1" 1>&2 exit 1 } cd /home/xxxx || error_exit "failed" rm -rf *
如上,这是一个非常简单的异常处理函数,在异常时,可以去主动调用error_exit,当然,你调用的时候,可以补充上行号信息。比如:
cd /home/xxxx || error_exit "$LINENO: failed"
上面讲得只是一些简单的异常处理的方式,其实还有其他方式,比如我在上篇文章shell中的trap和expr讲到的trap方式,其实也正是因为我上面文章写了trap,所以才想写这篇文章来把处理shell的异常给整理出来,当然也是为大家提个醒,在shell中,也是要处理异常,需要有这样一个意识。今天太晚了,先睡觉了,明早还要早起T.T
,下篇文章,PART 2中,我会详细总结下trap的捕获异常的方式。
安。
用trap处理异常
之前在《shell中的trap和expr》里简单得介绍过了trap,所以这次我们就直接上代码,上处理异常的代码,这样更加清晰明了,简单直接。先再重复下trap的使用方法吧:
trap [COMMAND] [SIGNAL]
代表trap会捕获信号[SIGNAL]后运行[COMMAND]
下面看段实例: #!/bin/bash trap “echo Fail unexpectedly on line \$FILENAME:\$LINENO!” ERR mkdir xxxx rm xxx
这段代码可以简单得说明了trap在处理异常的应用,后面那个ERR,就是捕获所有非0返回的shell执行,如果非0,那就是异常,就会被trap直接捕获,而不会继续往下执行了。在本文中的shell还会打印出文件名和行号等信息,当然,这些你可以自由发挥了。当然,trap其实不仅仅可以做这一件事情,还有好多事情,他可以捕获各种信号,当然除了SIGKILL,所以,你可以使用trap做一些其他事情。
扩展阅读-使用trap做工作环境的清理
什么是工作环境的清理呢,其实就是一般我们日常shell中可能会有各种临时文件,那留下这些文件总是不好的,所以你可以借用trap进行清理。我们看下下面这个shell程序#!/bin/bash TEMP_FILE=/tmp/printfile.txt pr $1 > $TEMP_FILE echo -n "Print file? [y/n]: " read if [ "$REPLY" = "y" ]; then less $TEMP_FILE fi rm $TEMP_FILE
这段代码的作用其实就是把用户一开始输入的存到一个临时文件里,然后询问下用户是否查看,如果查看就给print出来。当当然,用户看得话,没什么问题。看完了后,程序也就完了,临时文件也就删了。但关键是,如果程序在运行中异常终止了呢,或者用户直接按ctrl+C给终止了,这样,就会有一个临时文件留下。这个时候,你就可以去运用trap给你做些处理了。
#!/bin/bash TEMP_FILE=/tmp/printfile.txt trap "rm $TEMP_FILE; exit" SIGHUP SIGINT SIGTERM pr $1 > $TEMP_FILE echo -n "Print file? [y/n]: " read if [ "$REPLY" = "y" ]; then lpr $TEMP_FILE fi rm $TEMP_FILE
看上面这个程序,即使用户按下了ctrl+C ,trap也会可以捕获到,这样无论如何,临时文件都会被清理掉。
好了,就说这么多了,没啥技术含量,就是玩玩。
相关文章推荐
- 编写健壮的Bash shell脚本
- shell处理命令行选项getopts
- shellinabox:一款使用 AJAX 的基于 Web 的终端模拟器
- 关于使用mail命令产生:-bash: mail: command not found的解决方法
- 【Powershell】【Add-member】创建powershell对象
- shell 脚本教程--入门级
- 一些简单的shell脚本实例
- mac git+shell实现快速提交push
- FTP定时批量下载文件(SHELL脚本及使用方法 ) (转)
- Shell脚本学习笔记
- shell编程进阶
- --uva247(calling circles)强联通与floyd-warshell
- Linux基础知识--2.Linux的文件系统和bash的基础特性(1)
- 关于mongo的shell小贴士
- FTP定时批量下载文件(SHELL脚本及使用方法 )
- centos下一个bash: XXX: command not found解决方案
- linux新建用户切换后显示-bash-4.1$
- Windows下的calabash安装
- 杀死Linux Shell进程
- OK335xS U-boot 编译问题&无Linux shell 问题