Shell脚本中set -e和set -o pipefail的作用

前言

bash 复制代码
set -e
set -o pipefail

这个世界很多人的狂妄源于他并不知道自己不知道,所以才有了那句话:知道的越多实际上不知道的越多,今天文章的开头便甩了两行代码,这很不常见,本来这两天在忙着ClickHouse的搭建,想着搞完总结一下,但是牵扯的东西太多,所以先拿出今天发现的这个亮点记录一下,原来脚本还可以这么写。

set -e 的作用

只要脚本中有任意命令返回非 0 状态(失败),脚本就会立即退出,可以看下面这个例子

bash 复制代码
echo 1
cp not_exist_file /tmp/   # 假设这句失败
echo 2
  • 有 set -e:脚本执行到 cp 就马上退出,不会执行 echo 2
  • 没有 set -e:即使 cp 失败,脚本仍会继续执行 echo 2

它的意义就是防止错误被忽略,避免执行后续危险操作,特别适合以下场景

  • 下载失败不能继续
  • 解压失败不能继续
  • 数据导入失败不能继续

如果不用 set -e,为了阻止错误后继续执行,就得向下面这样写了

bash 复制代码
some_command
if [ $? -ne 0 ]; then
    echo "some_command failed"
    exit 1
fi

some_command || exit 1

some_command || { echo "failed"; exit 1; }

但是要注意,set -e 并不是对所有命令都触发,if 条件判断中的命令失败不会触发退出,比如下面这个命令执行错误

bash 复制代码
if grep keyword file.txt; then
   ...
fi

使用 set -e 面临的问题

开启 set -e 后,脚本自动退出,那我要如何打印出"是什么命令失败了"、"失败的原因"呢?

实际上,set -e 自己不会打印任何错误信息,只会在某个命令失败时直接退出脚本

有些命名失败时自己会输出的信息,比如 cp file1 file2 失败通常会打印 cp: cannot stat 'file1': No such file or directory

而专业的做法可以使用 trap 捕获错误并打印日志,比如可以在脚本开头加上这样一句

bash 复制代码
#!/bin/bash
set -e

trap 'echo "[ERROR] Command failed at line $LINENO: $BASH_COMMAND"' ERR

试验一下

编写一下测试脚本,执行

bash 复制代码
#!/bin/bash
set -e
set -o pipefail

trap 'echo "[ERROR] Command failed at line $LINENO: $BASH_COMMAND"' ERR

rm not_exist_file

运行结果如下:

bash 复制代码
$ ./testtrap.sh
rm: cannot remove 'not_exist_file': No such file or directory
[ERROR] Command failed at line 7: rm not_exist_file

除了rm命令本来的提示,trap给出了自定义提示,可以更加人性化

set -o pipefail 的作用

让管道命令的退出状态由"最右边命令"变成"整个管道中第一个失败的命令",使错误暴露出来不至于隐藏不见

示例代码如下

bash 复制代码
cat file.txt | grep "keyword"

假设:

  • cat file.txt 失败(文件不存在)
  • grep 依然成功(因为输入为空)

默认行为(不加 pipefail):

整个管道返回值是 grep 的,而 grep 是成功的 → 脚本认为整条命令成功

加上 pipefail 后:

整个命令返回 "cat file.txt 的失败",脚本能正确判断管道失败

结论

  • set -e 的作用是只要脚本中有任意命令返回非 0 状态(失败),脚本就会立即退出,避免继续执行引发更大错误
  • set -o pipefail 的作用是让管道命令的退出状态由"最右边命令"变成"整个管道中第一个失败的命令",避免某些管道错误会被悄悄忽略
  • 有些方案不知道时根本就不知道自己不知道,知道了就发现居然还有这种解法

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==


有些事就是那么巧,在我考虑将大量日志从MySQL迁移出时,评估了ClickHouse和Hive两个方向,最终选择了ClickHouse,之后突然发现合作商的SQL权限今天开了,一查他们也是ClickHouse,想到这里找人用同样的方法去查询了老东家的解决方案,居然是Hive,难道是英雄所见略同?哈哈~

相关推荐
AnxiangLemon10 天前
Warp Lite :一个专注本地使用的开源终端
终端·shell·warp·warp lite
sbjdhjd13 天前
从污点追踪断点到 PHP-FPM 请求队列:HIDS PHP WebShell 样本复盘
开发语言·网络安全·数据挖掘·渗透测试·开源·php·shell
Shell运维手记16 天前
Shell 结构化命令知识点总结(case、for、while)
运维·microsoft·shell·脚本
云计算练习生16 天前
什么是 Bash?Linux 默认 Shell 的核心功能
linux·操作系统·bash·shell·命令解释器
猫咪很可爱17 天前
MySQL 5.7 备份恢复后函数与存储过程丢失:原因分析与正确备份姿势
数据库·mysql·bug·shell
qetfw18 天前
Linux 文件清理:find、mtime 与安全传参验证
linux·shell·1024程序员节
Lsetea20 天前
curl下载HTTPS文件报23:证书验证成功与本地写入失败分层排查
linux·https·shell·ssl证书·curl
DogDaoDao21 天前
Windows 双 Shell 全面对比:CMD 与 PowerShell 的技术剖析
windows·shell·测试·powershell·cmd·程序员开发
Lsetea22 天前
OpenSSL的checkhost显示不匹配却退出0:名称检查与证书验收
linux·https·shell·ssl证书·openssl
钱栈up25 天前
耳机音效不对,我顺手查了系统更新,结果挖出个崩溃了整天的服务
windows·shell