查看: 101|回复: 0

Bash 脚本中的 set -euxo pipefail

[复制链接]
发表于 2020-2-15 21:58:08 | 显示全部楼层 |阅读模式
有些开辟职员会用Bash来实现很复杂的功能,就像使用别的高级语言一样。他可能觉得自己很牛逼但其他人早就想锤爆他了,Bash的可读性和可维护性远远低于任何高级语言。更要命的是,Bash并没有方便的调试工具和防错机制,出了问题你要排查半天。
在Ruby或者Python等高级语言里,你很轻易知道错误是哪行什么类型的错误,另有IDE的Debugger加持。而Bash只能看源码,通过打印log等非常低效的方式调试。
本文将介绍Bash中 set -euxo pipefail,它们可以资助你写出更轻易维护也更安全的脚本。这也是Bash脚本的终极调试手段,希望你以后在自己的脚本中加上这么一行,头顶也能少秃一点。
set -e

set -e 选项可以让你的脚本在出现异常时马上退出,后续命令不再实行。默认情况下Shell脚本不会因为错误而结束实行,但大多数情况是,我们希望出现异常时就不要再往下走了。假如你的if判断条件里会出现异常,这时脚本也会直接退出,但可能这并不是你期望的情况,这时你可以在判断语句后加上 || true 来阻止退出。
Before
  1. #!/bin/bash# 'foo' is a non-existing commandfooecho "bar"# output# ------# line 4: foo: command not found# bar
复制代码
After
  1. #!/bin/bashset -e# 'foo' is a non-existing commandfooecho "bar"# output# ------# line 5: foo: command not found
复制代码
阻止立刻退出的例子。
  1. #!/bin/bashset -e# 'foo' is a non-existing commandfoo || trueecho "bar"# output# ------# line 5: foo: command not found# bar
复制代码
set -o pipefail

默认情况下Bash只会查抄管道(pipeline)操作最后一个命令的返回值,假如最右边的命令成功那么它就认为这个语句没问题。这个行为其实是很不安全的,以是就有了set -o pipefail。这个特别的选项表示在管道连接的命令中,只要有任何一个命令失败(返回值非0),则整个管道操作被视为失败。只有管道中所有命令都成功实行了这个管道才算成功实行。
Before
  1. #!/bin/bashset -e# 'foo' is a non-existing commandfoo | echo "a"echo "bar"# output# ------# a# line 5: foo: command not found# bar
复制代码
After
  1. #!/bin/bashset -eo pipefail# 'foo' is a non-existing commandfoo | echo "a"echo "bar"# output# ------# a# line 5: foo: command not found
复制代码
set -u

set -u 比较轻易理解,Bash会把所有未界说的变量视为错误。默认情况下Bash会将未界说的变量视为空,不会报错,这也是很多坑的来源。大概由于变量名的细微差别让你查半天最后骂骂咧咧。
Before
  1. #!/bin/bashset -eo pipefailecho $aecho "bar"# output# ------## bar
复制代码
After
  1. #!/bin/bashset -euo pipefailecho $aecho "bar"# output# ------# line 5: a: unbound variable
复制代码
set -x

set -x 可以让Bash把每个命令在实行前先打印出来,你可以认为这就是Bash的Debug开关。它的利益固然显而易见,方便你快速找到有问题的脚本位置,但是也弊端也有吧,就是Bash的log会格外的乱。另外,它在打印命令前会把变量先剖析出来,以是你可以知道当前实行的语句的变量值是什么。纵然log可能会乱一些,总比头发乱一些好,以是发起还是打开这个开关。
  1. #!/bin/bashset -euxo pipefaila=5echo $aecho "bar"# output# ------# + a=5# + echo 5# 5# + echo bar# bar
复制代码
以上就是关于 set -euxo pipefail 的介绍,从Shell脚本的编写角度看,我十分发起所有人都应该在自己的Shell脚本里加上这么一行。但从实际情况看,如果你的Shell脚本已经凌驾200行,我更发起你换成高级语言来实现。比如Python或者Ruby乃至Perl,这些高级语言在Linux系统都是内置的,注意版本兼容性就好,写起来比Shell舒服太多了。
关于作者
Toby Qin, Python 技术爱好者,现在从事测试开辟相关工作,转载请注明原文出处。
欢迎关注我的博客 https://betacat.online,你可以到我的公众号中去当吃瓜群众

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?用户注册

x

相关技术服务需求,请联系管理员和客服QQ:2753533861或QQ:619920289
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

帖子推荐:
客服咨询

QQ:2753533861

服务时间 9:00-22:00

快速回复 返回顶部 返回列表