set 命令用于设置 Shell 的运行选项,可以改变脚本的行为。合理使用 set 选项,能让脚本更安全、更健壮,也更容易调试。
遇到错误立即退出。默认情况下,脚本会继续执行,即使某个命令失败了。
#!/bin/bash
set -e
mkdir /tmp/test
ls /notexist
echo "这行不会执行"
ls /notexist 失败后脚本立即退出。
使用未定义变量时报错。默认情况下,未定义变量会被当作空字符串。
#!/bin/bash
set -u
echo "姓名:$name"
运行结果:
script.sh: line 4: name: unbound variable
管道中任意命令失败,整个管道返回失败。默认只返回最后一个命令的状态。
#!/bin/bash
set -o pipefail
false | true
echo $?
运行结果:
1
如果没有 pipefail,$? 会是 0。
开启调试模式,打印执行的每条命令。
#!/bin/bash
set -x
name="张三"
echo "你好,$name"
推荐的组合:
#!/bin/bash
set -euo pipefail
这是编写健壮脚本的标准配置:
-e:错误退出-u:未定义变量报错-o pipefail:管道错误传播禁用文件名扩展(通配符):
set -f
echo *
输出 * 而不是文件列表。
只读取脚本不执行,用于语法检查:
set -n
显示读取的输入行:
set -v
禁止重定向覆盖已存在的文件:
set -C
echo "test" > file.txt # 如果 file.txt 存在会报错
echo "test" >| file.txt # 强制覆盖
缓存命令位置,加速命令查找:
set -h
set -o
set +o
set -o 以可读格式显示,set +o 以可重入格式显示。
用 + 代替 - 可以关闭选项:
#!/bin/bash
set -e
# 遇到错误退出
cmd1
# 临时禁用错误退出
set +e
cmd_might_fail
set -e
# 恢复错误退出
cmd2
| 简写 | 完整形式 |
|---|---|
| -e | -o errexit |
| -u | -o nounset |
| -x | -o xtrace |
| -v | -o verbose |
| -f | -o noglob |
| -n | -o noexec |
| -C | -o noclobber |
#!/bin/bash
set -euo pipefail
readonly SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
readonly SCRIPT_NAME=$(basename "${BASH_SOURCE[0]}")
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
error() {
log "错误:$*" >&2
exit 1
}
cleanup() {
log "清理资源..."
# 清理代码
}
trap cleanup EXIT
main() {
log "开始执行"
# 主逻辑
log "执行完成"
}
main "$@"
set -u 会让未定义变量报错,可以用默认值语法处理:
#!/bin/bash
set -u
name=${1:-"匿名"}
port=${PORT:-8080}
debug=${DEBUG:-false}
#!/bin/bash
set -e
# 这个命令可能失败,但不影响脚本继续执行
rm -f /tmp/temp || true
# 这个命令必须成功
important_command
#!/bin/bash
set -eo pipefail
# 如果 grep 没有匹配到内容,会返回非零状态
# 使用 || true 避免脚本退出
result=$(grep "pattern" file.txt || true)
# 或者检查结果
if ! grep -q "pattern" file.txt; then
echo "未找到匹配"
fi
set -e 的局限:
&& 或 || 中的错误#!/bin/bash
set -e
# 这个错误不会被捕获
false && echo "不会执行"
# 这个也不会
true || false
# 需要这样写
if ! false; then
echo "命令失败"
exit 1
fi
set -e 遇错退出,set -u 未定义变量报错set -o pipefail 管道错误传播set -euo pipefail 是推荐的组合set +e 临时禁用选项