Please enable Javascript to view the contents

Bash语法-Bash选项设置:Set命令

 ·  ☕ 4 分钟

相关博客

[Blog-1]: Bash语法-Bash选项设置:Set命令

[Blog-2]: Bash语法-Set与Export区分

1.简介

set命令用来修改 Shell 环境的运行参数,也就是定制环境。

运行参数会被保存在变量$-中,代表当前shell的选项设置。这些选项与set命令设置的选项相对应,它们定义了Shell 的行为和特性

例如,普通交互shell执行echo $-会返回himBHs,z这意味着shell启用了选项:

  • h: hashall 选项,使得 Bash 在可执行命令之前,总是执行路径哈希。这可以提高执行命令的速度(因为 Bash 会缓存命令的路径)。
  • i: Interactive选项,表示这是一个交互式 shell。
  • m:monitor 选项,使得 Bash 在执行命令时,允许作业控制信号(如 SIGTTIN、SIGTTOU)被传递给被控制的进程。
  • B:nobraceexpand 选项,禁止 Bash 对大括号 {} 内的表达式进行扩展,即使它们包含空格或由空格分隔的多个单词。
  • H:histexpand 选项,允许 Bash 对历史扩展进行扩展,即使 shell 不是交互式的。
  • s:shell 选项,使得 Bash 在读取命令行时,允许 shell 脚本中的特殊字符和引用被解释。

2.使用

顺便提一下,如果命令行下不带任何参数,直接运行set,会显示所有的环境变量和 Shell 函数

常用的四个命令如下

选项(简写)详细格式说明
set -o通过选项名称修改Bash选项设置
set -uset -o nounset引用空变量时,立即报错退出。用于避免因使用了未初始化变量而导致的错误
set -xset -o xtrace在打印结果前,先打印命令
set -eset -o errexit发生错误,立即终止
set -o pipefail管道子命令发生错误,立即终止

2.1 检查变量是否为空

当引用空变量时,立即报错退出。用于避免因使用了未初始化变量而导致的错误。

1
set -u

2.2 在打印结果之前,先打印命令。

在运行结果之前,先输出执行的命令。

1
set -x

2.3 错误处理

Bash默认配置时,脚本命令执行失败,仍会继续执行后面的命令。会导致错误累积,不利于脚本维护调试。
set -e会使脚本发生错误时,立刻终止退出。

2.3.1 || + exit 1,默认设置下的异常处理

  1. 通过逻辑或 + || + exit 1

通过下面写法,当command有非零返回值,脚本就会停止执行。防止错误累积

bash首先执行左侧command,如果command执行成功(返回状态0),则exit 1不被执行;如果command执行失败(返回状态非0),则执行exit 1

1
command || exit 1

也可在退出时增加日志打印:

1
command || { echo "command failed"; exit 1; }
  1. 通过判断命令退出码,打印日志并退出shell
1
if ! command; then echo "command failed"; exit 1; fi

等同于

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

2.3.2 set -e,异常处理

脚本只要发生错误,就终止执行。但对|管道失效,具体原因看 2.4 小节

1
2
set -e
command

2.3.3 例外:命令执行成功,但返回状态非0

如果脚本中,部分命令的返回非空是正常情况,则需要临时关闭set -e,来让脚本正常执行。

  1. 通过set +e关闭选项,之后再通过set -e打开
1
2
3
4
5
6
7
8
9
#!/usr/bin/env bash
set -e
echo "初始设置 set -e 并执行命令"

# 临时关闭 set +e
set +e
echo "执行正常返回为非空的命令"
# 重新打开 set -e
set -e
  1. 通过逻辑或||,忽略命令的返回状态

左侧命令执行返回非零时,执行右侧命令,右侧是echotrue等返回状态为0的命令,会使整体命令返回状态0,使脚本正常执行。注意与 2.3.1 || exit 1 区分

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

echo "执行正常返回为非空的命令" || true
echo "执行正常返回为非空的命令" || echo "Skip status check"

2.4 子命令失败,整个管道命令就失败,脚本就会终止执行。

管道命令,就是多个子命令通过管道运算符|()组合成为一个大的命令。Bash会把最后一个子命令的返回值,作为整个命令的返回值。
也就是说,只要最后一个子命令不失败,管道命令总是会执行成功,因此它后面命令依然会执行,set -e 就失效了。
例如

1
2
3
4
5
#!/usr/bin/env bash
set -e
# 由于下面`echo "test"`成功,命令永远不会中断
mc | echo "test"
echo bar

改为如下写法,解决管道问题

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

foo | echo a
echo bar

还有一种会导致set -e失效,mkdir /aa/bb/cc || true,此处的||逻辑或,效果是只要有一个命令不失败,则整体也不会失败(即,echo $?为0)

3. 推荐设置

推荐设置:

  • -u, 校验空变量, 即避免变量未初始化
  • -x, 输出结果前先打印命令
  • -e, 发生错误,立即终止
  • -o pipefail, 管道子命令发生错误,立即终止

3.1 Bash脚本内设置

1
set -euxo pipefail

等同于

1
2
set -eux
set -o pipefail

3.2 命令行执行脚本时,增加选项

1
bash -euxo pipefail script.sh

4. 参考链接

[注1]: linux-Set命令说明

[注2]: Bash脚本set命令教程-阮一峰

分享

Hex
作者
Hex
CloudNative Developer

目录