• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >linux shell > 如何编写健壮的Bash脚本(经验分享)

如何编写健壮的Bash脚本(经验分享)

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了编写bash脚本,bash脚本,linux bash脚本,高级bash脚本编程指南,bash脚本编程等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

shell脚本在运行异常时会受到非常大的影响。

本文介绍一些让bash脚本变得健壮的技术。

使用set -u

因为没有对变量初始化而使脚本崩溃过多少次?对于我来说,很多次。
chroot=$1
...
rm -rf $chroot/usr/share/doc
如果上面的代码没有给参数就运行,不会仅仅删除掉chroot中的文档,而是将系统的所有文档都删除。那应该做些什么呢?好在bash提供了set -u,当使用未初始化的变量时,让bash自动退出。

也可以使用可读性更强一点的set -o nounset。

使用set -e

写的每一个脚本的开始都应该包含set -e。这告诉bash一但有任何一个语句返回非真的值,则退出bash。使用-e的好处是避免错误滚雪球般的变成严重错误,能尽早的捕获错误。更加可读的版本:set -o errexit

使用-e把从检查错误中解放出来。如果忘记了检查,bash会替做这件事。不过也没有办法使用$?来获取命令执行状态了,因为bash无法获得任何非0的返回值。可以使用另一种结构:

command

if [ "$?"-ne 0]; then echo "command failed"; exit 1; fi

可以替换成:

command || { echo "command failed"; exit 1; }

或者使用:

if ! command; then echo "command failed"; exit 1; fi

如果必须使用返回非0值的命令,或者对返回值并不感兴趣呢?可以使用 command || true ,或者有一段很长的代码,可以暂时关闭错误检查功能,不过我建议谨慎使用。

set +e

command1

command2

set -e

相关文档指出,bash默认返回管道中最后一个命令的值,也许是不想要的那个。比如执行 false | true 将会被认为命令成功执行。如果想让这样的命令被认为是执行失败,可以使用 set -o pipefail

程序防御 - 考虑意料之外的事

的脚本也许会被放到“意外”的账户下运行,像缺少文件或者目录没有被创建等情况。可以做一些预防这些错误事情。比如,当创建一个目录后,如果父目录不存在,mkdir 命令会返回一个错误。如果创建目录时给mkdir命令加上-p选项,它会在创建需要的目录前,把需要的父目录创建出来。另一个例子是rm 命令。如果要删除一个不存在的文件,它会“吐槽”并且的脚本会停止工作。(因为使用了-e选项,对吧?)可以使用-f选项来解决这个问题,在文件不存在的时候让脚本继续工作。

准备好处理文件名中的空格

有些人从在文件名或者命令行参数中使用空格,需要在编写脚本时时刻记得这件事。需要时刻记得用引号包围变量。

if [ $filename = "foo" ];

当$filename变量包含空格时就会挂掉。可以这样解决:

if [ "$filename" = "foo" ];

使用$@变量时,也需要使用引号,因为空格隔开的两个参数会被解释成两个独立的部分。

我没有想到任何不能使用"$@"的时候,所以当有疑问的时候,使用引号就没有错误。

如果同时使用find和xargs,应该使用 -print0 来让字符分割文件名,而不是换行符分割。

设置的陷阱

当编写的脚本挂掉后,文件系统处于未知状态。比如锁文件状态、临时文件状态或者更新了一个文件后在更新下一个文件前挂掉。如果能解决这些问题,无论是 删除锁文件,又或者在脚本遇到问题时回滚到已知状态,都是非常棒的。幸运的是,bash提供了一种方法,当bash接收到一个UNIX信号时,运行一个 命令或者一个函数。可以使用trap命令。

trap command signal [signal ...]

可以链接多个信号(列表可以使用kill -l获得),但是为了清理残局,我们只使用其中的三个:INT,TERM和EXIT。可以使用-as来让traps恢复到初始状态。

信号描述
INT
Interrupt - 当有人使用Ctrl-C终止脚本时被触发

TERM
Terminate - 当有人使用kill杀死脚本进程时被触发

EXIT
Exit - 这是一个伪信号,当脚本正常退出或者set -e后因为出错而退出时被触发

当使用锁文件时,可以这样写:

当最重要的部分(critical-section)正在运行时,如果杀死了脚本进程,会发生什么呢?
锁文件会被扔在那,而且的脚本在它被删除以前再也不会运行了。

解决方法:

现在当杀死进程时,锁文件一同被删除。注意在trap命令中明确地退出了脚本,否则脚本会继续执行trap后面的命令。

竟态条件 (wikipedia)

在上面锁文件的例子中,有一个竟态条件是不得不指出的,它存在于判断锁文件和创建锁文件之间。一个可行的解决方法是使用IO重定向和bash的noclobber(wikipedia)模式,重定向到不存在的文件。

可以这么做:

更复杂一点儿的问题是要更新一大堆文件,当它们更新过程中出现问题时,是否能让脚本挂得更加优雅一些。想确认那些正确更新了,哪些根本没有变化。比如需要一个添加用户的脚本。

当磁盘空间不足或者进程中途被杀死,这个脚本就会出现问题。在这种情况下,也许希望用户账户不存在,而且他的文件也应该被删除。


rollback() {
del_from_passwd $user
if [ -e /home/$user ]; then
rm -rf /home/$user
fi
exit
}

trap rollback INT TERM EXIT
add_to_passwd $user

cp -a /etc/skel /home/$user
chown $user /home/$user -R

trap - INT TERM EXIT
</div>

在脚本最后需要使用trap关闭rollback调用,否则当脚本正常退出的时候rollback将会被调用,那么脚本等于什么都没做。

保持原子化

又是需要一次更新目录中的一大堆文件,比如需要将URL重写到另一个网站的域名。
也许会写:

代码如下:</div>

您可能想查找下面的文章:

  • Bash脚本内置的调试方法技巧
  • bash脚本中if语句的使用方法
  • 如何编写健壮的Bash脚本(经验分享)
  • bash脚本输入密码不回显问题的解决方法

相关文章

  • 阿里云云服务器Linux系统更新yum源Shell脚本
  • Csh的基本语法介绍
  • linux dev 常见特殊设备介绍与应用(loop,null,zero,full,random)
  • linux命令scp和sftp详细介绍
  • Linux 脚本编写基础知识
  • 浅谈Linux 脚本 sh 和 ./ 的区别
  • shell脚本联合PHP脚本采集网站的pv和alexa排名
  • Linux下查找后门程序 CentOS 查后门程序的shell脚本
  • Linux Shell脚本系列教程(七):脚本调试
  • Shell脚本切割tomcat的日志文件

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • linux使用管道命令执行ps获取cpu与内存占用率
    • php在linux中可能用到的命令(推荐)
    • shell按行读取文件的3种方法
    • shell脚本中取消重定向的方法实例
    • 用shell命令读取与输出数据的代码
    • shell中的各种括号的使用方法
    • Cygwin下安装vim后,vim中退格键无法正常使用的解决方法
    • awk中查看包含某两列字符的用法
    • 一个监控LINUX目录和文件变化的Shell脚本分享
    • 详解Linux命令中的正则表达式

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有