文章目录
- 1、简述
- 2、脚本执行过程
- 3、set
- 3.1 set -u
- 3.2 set-x
- 3.3 set -e
- 3.4 set -o pipefail
- 3.5 总结
- 3.6 取消Bash参数调优
1、简述
Linux服务器脚本开发和运维管理常使用Bash脚本,经常遇到以下场景:
- 未定义变量shell内默认设置为空,导致未定义变量被滥用;
- Shell脚本执行过程未知,若无具体返回值时将无法确认执行过程是否正常;
- 脚本命令中若存在错误,将继续执行后续命令,导致脚本执行过程发生不可扭转错误;
正因为前述多个场景下问题难以解决,因此更需了解Bash脚本的使用与调优方法,可有效降低脚本执行的安全性与可维护性。
2、脚本执行过程
例如:使用Bash执行某个脚本。
[root@localhost ~]# bash test.sh
aaa
上述命令中,test.sh
为shell脚本名称,Bash执行时将创建一个新的shell进行执行,此shell即脚本的执行环境,Bash默认定义了这个shell的各种参数,可使用set直接查看赋予的所有参数(返回内容较多,建议重定向到文件内查看)
3、set
set
- 用于设置shell执行环境参数
语法格式:
set: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
set可设置shell参数较多,使用set --help
查看。
本文仅介绍常用的四个参数
3.1 set -u
执行Bash脚本时遇到未定义的变量时报错
[root@localhost ~]# cat test.sh
#!/bin/bashbbb=bbb
echo $aaa
echo $bbb
[root@localhost ~]# bash test.sh # 未定义变量输出为空行,后续命令继续执行
bbb
# 使用set -u后
[root@localhost ~]# vim test.sh
#!/bin/bash
set -ubbb=bbb
echo $aaa
echo $bbb
[root@localhost ~]# bash test.sh
test.sh: line 5: aaa: unbound variable # 未定义变量报错,后续命令不在执行
3.2 set-x
回显Bash脚本执行过程,以+
代表执行过程,未携带则代表执行结果。
[root@localhost ~]# vim test.sh
#!/bin/bashbbb=bbb
echo $bbb
[root@localhost ~]# bash test.sh
bbb
[root@localhost ~]# bash -x test.sh
+ bbb=bbb # 执行过程
+ echo bbb
bbb # 执行结果
3.3 set -e
当Bash脚本内存在命令执行错误时(返回值非0),Bash会继续执行后面命令。
[root@localhost ~]# vim test.sh
#!/bin/bashaaa
echo bbb
[root@localhost ~]# bash test.sh
test.sh: line 3: aaa: command not found
bbb
上面脚本中aaa为一个不存在的命令,但是Bash会忽略这个错误继续执行下面的命令,实际开发中,如果某个命令失败,往往需要脚本停止执行,防止错误累积。这时,一般采用下面的写法
[root@localhost ~]# aaa || exit 1
上面的写法表示只要aaa有非零返回值,脚本就会停止执行。
常用的错误处理方法有以下几种:
# 写法一
aaa|| { echo "aaa failed"; exit 1; }# 写法二
if ! aaa; then echo "aaafailed"; exit 1; fi# 写法三
aaa
if [ "$?" -ne 0 ]; then echo "aaa failed"; exit 1; fi
前述方法书写较为麻烦,set从根本解决上述问题,使用set -e
可以直接解决这个问题,它使得脚本只要发生错误,就终止执行。
[root@localhost ~]# cat test.sh
#!/bin/bash
set -eaaa
echo bbb
[root@localhost ~]# bash test.sh
test.sh: line 4: aaa: command not found # 执行到错误时,脚本自动停止不在执行后面命令
3.4 set -o pipefail
set -e
存在一个特例,多个子命令通过管道运算符|
组合成为一个大的命令时。Bash会将最后一个子命令的返回值,作为整个命令的返回值。只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,因此set -e
就失去效果了。
[root@localhost ~]# vim test.sh
#!/bin/bash
set -eaaa | echo aaa
echo bbb
[root@localhost ~]# bash test.sh
test.sh: line 4: aaa: command not found
aaa
bbb
因此set -o pipefail
用来解决这种情况,只要一个子命令失败,整个管道命令就失败,脚本就会终止执行
[root@localhost ~]# vim test.sh
#!/bin/bash
set -eo pipefailaaa | echo aaa
echo bbb
[root@localhost ~]# bash test.sh
aaa
test.sh: line 4: aaa: command not found # 管道符其中一个子命令执行失败则整个命令失败,无法继续执行
3.5 总结
set
命令的上面这四个参数,一般都放在一起使用。
set -euxo pipefail
或在执行时带入参数
bash -euxo pipefail test.sh
3.6 取消Bash参数调优
取消设置如下:
set +e # 使用+号可以取消参数设置
set +euxo pipefail