0%

Linux Set命令

背景

​ 有时候在执行shell脚本的时候,在运行/调试的过程中会有些报错看起来不是太明显,那如何高效的调试自己编写的shell脚本呢??

解决方案

​ 网上有一些解决方案,但是尝试了下后觉得使用 shell 中的 set 命令来解决更加方便和快捷。下面来看看 set 命令到底能够有哪些应用场景。

(1)set -u

​ 执行脚本的时候,有时候会遇到变量未定义(如:拼写错误导致变量未定义),Bash 默认是忽略它并且继续执行的,在某些场景这可能会对后面的脚本造成不可预期的错误操作, 所以可以通过 set -u 来控制,具体案例如下:

1
2
3
4
5
6
7
#!/usr/bin/bash

echo $a
echo bar
$ bash set_test.sh

bar

​ 可以看到,echo $a 输出了一个空行,Bash 忽略了不存在的 $a,然后继续执行 echo bar。大多数情况下,这不是开发者想要的行为,遇到变量不存在,脚本应该报错,而不是一声不响地往下执行。

通过脚本在头部加上 set -u 后,遇到不存在的变量就会报错,并停止执行。

1
2
3
4
5
6
7
#!/usr/bin/bash
set -u

echo $a
echo bar
$ bash set_test.sh
set_test.sh: line 4: a: unbound variable

(2)set -x

​ 在执行复杂脚本的时候,需要对脚本进行类似debug一样的操作,则可以通过设置 set -x,这样就会对脚本中的执行过程的变量以及具体执行的代码进行输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/bash
set -x

name="tester"
if [[ ${name} == "tester" ]];then
echo "hello"
else
echo "failed..."
fi

echo end
$ bash set_test.sh
+ name=tester
+ [[ tester == \t\e\s\t\e\r ]]
+ echo hello
hello
+ echo end
end

​ 可以看到,在进行条件判断的时候,变量name被具体值替换了,打印了代码走到了条件分支的哪一步,以及打印了相应的有输出的代码行,行首以+表示。这对于调试复杂的脚本是很有用的。

(3)set -e

​ 如果脚本里面有运行失败的命令(返回值非0),Bash 默认会继续执行后面的命令,在实际开发中,这种会导致比较严重的影响。

1
2
3
4
5
6
7
#!/usr/bin/bash

foo
echo bar
$ bash set_test.sh
set_test.sh: line 5: foo: command not found
bar

通过使用 set -e 则可以运行失败的命令就直接退出。

1
2
3
4
5
6
7
#!/usr/bin/bash
set -e

foo
echo bar
$ bash set_test.sh
set_test.sh: line 6: foo: command not found

也可以通过下面的方式来指定具体某个代码块运行失败后自动退出。

1
2
3
4
set -e      # 表示打开遇到运行命令返回非0则退出
command1
command2
set +e # 表示关闭遇到运行命令返回非0则退出

(4)set -o pipefail

set -e 有一个例外情况,就是不适用于管道命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。也就是说,只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e 就失效了。

1
2
3
4
5
6
7
8
9
#!/usr/bin/bash
set -e

foo | echo a
echo bar
$ bash set_test.sh
set_test.sh: line 7: foo: command not found
a
bar

​ 上面代码中,foo是一个不存在的命令,但是 foo | echo a 这个管道命令会执行成功,导致后面的 echo bar 会继续执行。

set -eo pipefail 用来解决这种情况,只要一个子命令失败,整个管道命令就失败,脚本会在该管道执行完后终止执行。

1
2
3
4
5
6
7
8
#!/usr/bin/bash
set -eo pipefail

foo | echo a
echo bar
$ bash set_test.sh
set_test.sh: line 7: foo: command not found
a

​ 可以看出,管道任务失败后,echo bar则未进行执行。

总结

​ set命令的上面这四个参数,一般都放在一起使用,常用的两种方式如下:

1
2
3
4
5
6
# 写法一
set -euxo pipefail

# 写法二
set -eux
set -o pipefail
------------- 本 文 结 束 感 谢 您 的 阅 读 -------------