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,难道是英雄所见略同?哈哈~

相关推荐
pluvium2721 小时前
记对 xonsh shell 的使用, 脚本编写, 迁移及调优
linux·python·shell·xonsh
ShineWinsu3 天前
对于Linux:文件操作以及文件IO的解析
linux·c++·面试·笔试·io·shell·文件操作
Cyber4K4 天前
【Shell专项】循环及交互的使用
linux·shell
vangie12 天前
你还在手敲长命令?这个 Shell 插件帮你自动提醒别名和现代替代工具
shell·命令行
哈里谢顿15 天前
服务器操作卡顿问题解决
shell
狂龙骄子20 天前
CentOS查看压缩包文件列表
shell·rar·7-zip·cygwin·7z·压缩包文件列表·查看压缩包
波特率1152001 个月前
bash命令进阶学习(Shell 元字符)
linux·bash·shell
阿常呓语1 个月前
Linux命令 jq详解
linux·运维·shell·jq
buhuimaren_1 个月前
Shell循环语句
shell
IMPYLH1 个月前
Bash 的 basenc 命令
linux·运维·服务器·bash·shell