set 是 Bash 和其他现代 Shell 中一个内置的、非常强大的命令,它的主要功能是 设置或取消设置 Shell 选项,以及 显示 Shell 变量,理解 set 命令是掌握 Shell 高级用法的关键。

set 命令的语法主要有以下几种形式:
set [--abefhkmnptuvxBCHP] [arg ...] set +o option_name set -o
下面我们分点来详细解释。
显示所有 Shell 变量和函数(不带任何选项)
当你直接输入 set 命令而不带任何选项时,它会打印出当前 Shell 环境中所有的 Shell 变量、函数和位置参数。
示例:

$ set
BASH=/bin/bash
BASH_VERSION=5.1.16(1)-release
...
_=/usr/bin/set
my_var="hello world"
func ()
{
echo "This is a function"
}
输出解读:
BASH,BASH_VERSION等:是 Shell 自动创建的环境变量。_=/usr/bin/set:最后一个执行的命令的路径。my_var="hello world":是你自己定义的变量。func ...:是你定义的函数。
这个功能通常用于调试,查看当前 Shell 的完整状态。
设置 Shell 选项( 开头)
使用 set -<option_letter> 的形式可以启用一个或多个 Shell 选项,这些选项极大地改变了 Shell 的行为,使其更严格、更安全或更符合你的预期。
常用且重要的选项
| 选项 | 全称 | 描述 | 强烈推荐 |
|---|---|---|---|
-e |
errexit |
如果任何命令以非零状态退出,则立即退出。 这是最重要的安全选项之一,可以防止脚本在出错后继续执行导致更严重的问题。 | 是 |
-u |
nounset |
尝试使用未定义的变量时,Shell 会报错并退出。 可以防止因变量名拼写错误(log_file 写成 log_fie)而引入的、难以发现的逻辑错误。 |
是 |
-o pipefail |
pipefail |
管道中的任何一个命令失败,整个管道的返回值都将是非零。 默认情况下,管道的返回值是最后一个命令的返回值,这个选项让管道的错误处理更符合逻辑。 | 是 |
-x |
xtrace |
打印执行的命令及其参数。 在调试脚本时非常有用,可以清楚地看到 Shell 是如何解析和执行你的命令的。 | 调试时 |
-a |
allexport |
导出所有后续创建或修改的变量。 相当于在每个 variable=value 赋值语句前都加上 export。 |
较少用 |
-f |
noglob |
禁止文件名通配(globbing)。 , , [] 等将作为普通字符。 |
较少用 |
-C |
noclobber |
防止覆盖已存在的文件(在使用 > 重定向时)。 如果文件已存在,命令会失败,如果想强制覆盖,可以使用 >|。 |
有时 |
实践示例
场景:一个不安全的脚本

#!/bin/bash # script.sh echo "Starting script..." # 假设这个命令失败了 false echo "This line should not be printed if the command above failed." cp important_file.txt /some/destination/ # 如果目标目录不存在,这个命令会失败 echo "Script finished."
运行这个脚本:
$ ./script.sh Starting script... This line should not be printed if the command above failed. cp: cannot create regular file '/some/destination/important_file.txt': No such file or directory Script finished.
可以看到,即使 false 和 cp 命令都失败了,脚本依然继续执行,导致了错误。
改进:使用 set -e
#!/bin/bash set -e # 启用 errexit 选项 echo "Starting script..." false # 这个命令返回非零,脚本将在这里终止 echo "This line will NOT be printed."
运行改进后的脚本:
$ ./script.sh Starting script.
脚本在 false 命令执行后立即退出,后续的代码不会被执行。
组合使用 -e, -u, -o pipefail
这是编写健壮脚本的黄金组合。
#!/bin/bash set -euo pipefail # -e: 任何命令失败则退出 # -u: 使用未定义变量则报错退出 # -o pipefail: 管道中任何命令失败则管道失败 echo "Processing data..." # 假设 data.txt 不存在 cat data.txt | grep "error" > output.log echo "This line will not be reached."
data.txt 不存在,cat data.txt 会失败,由于 -o pipefail,整个管道失败,-e 选项导致脚本立即退出。
取消设置 Shell 选项( 开头)
使用 set +<option_letter> 的形式可以禁用一个之前启用的选项。
示例:
#!/bin/bash set -x # 启用调试模式 echo "Debugging is ON." echo "This command will be printed." set +x # 禁用调试模式 echo "Debugging is now OFF." echo "This command will NOT be printed."
输出:
+ echo 'Debugging is ON.' Debugging is ON. + echo 'This command will be printed.' This command will be printed. Debugging is now OFF. echo "This command will NOT be printed."
可以看到,set +x 之后的命令不再被打印。
使用 -o 选项名进行设置和查看
set 命令也支持使用长选项名来设置和查看选项,这种方式更具可读性。
设置选项
set -o errexit # 等同于 set -e set -o nounset # 等同于 set -u set -o pipefail # 等同于 set -o pipefail
查看选项状态
输入 set -o 会列出所有可用的选项及其当前状态(on 或 off)。
$ set -o allexport off braceexpand on emacs on errexit off # -e 选项是关闭的 ... pipefail off # pipefail 选项是关闭的 ... xtrace off # -x 选项是关闭的
使用 +o 禁用选项
set +o errexit # 等同于 set +e
设置位置参数
set 命令还可以用来设置脚本的位置参数(即 $1, $2, ... 等)。
语法:
set -- arg1 arg2 arg3 ...
示例:
#!/bin/bash # 先查看初始的位置参数 echo "Initial arguments: $@" # 使用 set 设置新的位置参数 set -- "apple" "banana" "cherry" echo "New arguments: $@" echo "First argument: $1" echo "Number of arguments: $#"
输出:
Initial arguments: New arguments: apple banana cherry First argument: apple Number of arguments: 3
是一个重要的分隔符,它告诉 set 命令后面的所有参数都应被视为位置参数,而不是选项,这可以防止参数(如 -e)被误解为选项。
最佳实践和总结
- 在脚本开头使用
set -euo pipefail:这是编写健壮、可靠脚本的基石,它能帮你捕获绝大多数常见的错误。 - 仅在调试时使用
set -x:当脚本行为不符合预期时,在开头加上set -x来查看详细的执行流程,调试完成后记得用set +x关闭,或者使用一个调试函数来控制。 - 使用
set查看状态:当你不确定某个选项是否开启,或者想查看所有变量时,直接运行set是最简单的方法。 - 注意选项的兼容性:虽然
-euo pipefail在 Bash 中是标准,但在非常古老的 Shell(如sh)或某些非 Bash Shell(如dash)中可能不支持,如果你的脚本需要在多种环境下运行,请进行测试或使用替代方案。
通过灵活运用 set 命令,你可以让 Shell 脚本变得更加健壮、安全和易于调试。
