set 命令

  • Bash 执行脚本时,会创建一个子 Shell。这个子 Shell 就是脚本的执行环境,Bash 默认给定了这个环境的各种参数。

  • set 命令用来修改子 Shell 环境的运行参数,即定制环境。

set -u

before

执行脚本时,如果遇到不存在的变量,Bash 默认忽略它。

1
2
3
4
#!/usr/bin/env bash

echo $a
echo bar

上面代码中,$a是一个不存在的变量。执行结果如下。

1
2
3
$ bash script.sh

bar

after

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

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

echo $a
echo bar

运行结果如下。

1
2
$ bash test.sh
bash: script.sh: line 4: a: unbound variable

-u 还有另一种写法 -o nounset,两者是等价的。

1
set -o nounset

set -x

  • 用来在运行结果之前,先输出执行的那一行命令。
1
2
3
4
5
#!/usr/bin/env bash
set -x

echo $a
echo bar

执行上面的脚本,结果如下。

1
2
3
4
5
$ ./test.sh
+ echo

+ echo bar
bar
  • -x 还有另一种写法 -o xtrace
1
set -o xtrace
  • 脚本当中如果要关闭命令输出,可以使用set +x

set -e

set -e 使得脚本只要发生错误,就终止执行。

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

foo
echo bar

执行结果如下。

1
2
$ bash script.sh
script.sh:行4: foo: 未找到命令

set -e根据返回值来判断,一个命令是否运行失败。但是,某些命令的非零返回值可能不表示失败,或者开发者希望在命令失败的情况下,脚本继续执行下去。这时可以暂时关闭 set -e,该命令执行结束后,再重新打开set -e

1
2
3
4
set +e
command1
command2
set -e

set +e 表示关闭 -e 选项,set -e 表示重新打开 -e 选项。

还有一种方法是使用command || true,使得该命令即使执行失败,脚本也不会终止执行。

  • -e还有另一种写法-o errexit
1
set -o errexit

set -o pipefail

  • set -e有一个例外情况,就是不适用于管道命令
  • 所谓管道命令,就是多个子命令通过管道运算符(|)组合成为一个大的命令。Bash 会把最后一个子命令的返回值,作为整个命令的返回值。
1
2
3
4
5
#!/usr/bin/env bash
set -e

foo | echo a
echo bar

执行结果如下。

1
2
3
4
$ bash script.sh
a
script.sh:行4: foo: 未找到命令
bar

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

1
2
3
4
5
#!/usr/bin/env bash
set -eo pipefail

foo | echo a
echo bar

运行后,结果如下。

1
2
3
$ bash script.sh
a
script.sh:行4: foo: 未找到命令