菜鸟科技网

shell set命令的用法有哪些?不同选项如何影响脚本执行行为?

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

shell set命令的用法有哪些?不同选项如何影响脚本执行行为?-图1
(图片来源网络,侵删)

set 命令的语法主要有以下几种形式:

set [--abefhkmnptuvxBCHP] [arg ...]
set +o option_name
set -o

下面我们分点来详细解释。


显示所有 Shell 变量和函数(不带任何选项)

当你直接输入 set 命令而不带任何选项时,它会打印出当前 Shell 环境中所有的 Shell 变量函数位置参数

示例:

shell set命令的用法有哪些?不同选项如何影响脚本执行行为?-图2
(图片来源网络,侵删)
$ 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 防止覆盖已存在的文件(在使用 > 重定向时)。 如果文件已存在,命令会失败,如果想强制覆盖,可以使用 >| 有时

实践示例

场景:一个不安全的脚本

shell set命令的用法有哪些?不同选项如何影响脚本执行行为?-图3
(图片来源网络,侵删)
#!/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.

可以看到,即使 falsecp 命令都失败了,脚本依然继续执行,导致了错误。

改进:使用 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 会列出所有可用的选项及其当前状态(onoff)。

$ 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)被误解为选项。


最佳实践和总结

  1. 在脚本开头使用 set -euo pipefail:这是编写健壮、可靠脚本的基石,它能帮你捕获绝大多数常见的错误。
  2. 仅在调试时使用 set -x:当脚本行为不符合预期时,在开头加上 set -x 来查看详细的执行流程,调试完成后记得用 set +x 关闭,或者使用一个调试函数来控制。
  3. 使用 set 查看状态:当你不确定某个选项是否开启,或者想查看所有变量时,直接运行 set 是最简单的方法。
  4. 注意选项的兼容性:虽然 -euo pipefail 在 Bash 中是标准,但在非常古老的 Shell(如 sh)或某些非 Bash Shell(如 dash)中可能不支持,如果你的脚本需要在多种环境下运行,请进行测试或使用替代方案。

通过灵活运用 set 命令,你可以让 Shell 脚本变得更加健壮、安全和易于调试。

分享:
扫描分享到社交APP
上一篇
下一篇