每个开发者都应该知道的 Bash 脚本技巧

引言:Bash 是你一直忽视的技能

大多数开发者"了解" Bash 的方式就像他们"了解" Git 一样:仅够应付。记住几个命令,从 Stack Overflow 复制脚本,按下回车前默默祈祷。

但 Bash 不仅仅是 Linux 爱好者或 DevOps 人员的胶水语言。它是自动化、调试、部署、数据处理以及无数日常任务背后的隐形力量。慢速开发者和高效开发者之间的差异,往往取决于他们对 shell 的掌握程度。

本文不是关于记忆晦涩的参数。而是关于实用的 Bash 脚本技巧——小想法带来巨大影响。这些技巧让你的脚本更安全、更整洁、更易维护。这些是你希望多年前就有人告诉你的东西。

让我们磨练你的终端直觉。

始终在"严格模式"下启动脚本

大多数 Bash 脚本会静默失败。这很危险。

每个开发者都应该知道的第一个技巧是在脚本顶部启用严格模式:

bash
set -euo pipefail

这一行代码的作用:

  • -e:命令失败时立即退出
  • -u:将未设置的变量视为错误
  • -o pipefail:如果管道中任何命令失败则失败

没有这个设置,你的脚本可能执行到一半就出错了,但还会继续运行,就像什么都没发生一样。有了严格模式,失败会立即且明显——这正是自动化中你想要的。

可以把它理解为将 Bash 的运行时错误转变为编译时错误。

使用 "$@" 而不是 $*(是的,这很重要)

如果你的脚本接受参数,这个细节可以为你节省数小时的调试时间。

始终使用:

bash
"$@"

而不是:

bash
$*

为什么?因为 "$@" 保留参数边界。空格保持完整。文件名不会被拆分成碎片。当用户传递带引号的字符串时,你的脚本会正确运行。

这是那些看起来很迂腐的 Bash 规则之一——直到它在生产环境中破坏了重要的东西。

认真命名你的变量

Bash 没有类型,但命名是你的安全网。

不好的做法:

bash
x=10
y="file.txt"

更好的做法:

bash
MAX_RETRIES=10
INPUT_FILE="file.txt"

为什么用大写?因为 Bash 约定将大写变量视为常量或配置。这也有助于避免与环境变量或命令名称冲突。

好的变量名将脆弱的脚本转变为可读的程序。

使用 $(...) 而不是反引号

如果你还在使用反引号,是时候放弃它们了。

旧写法:

bash
files=`ls`

现代写法:

bash
files=$(ls)

使用 $(...) 进行命令替换的优势:

  • 更易读
  • 更易嵌套
  • 更少出错

这不仅仅是语法偏好。这关乎编写随着增长而不会与你作对的 Bash 代码。

使用明确的错误消息快速失败

当出现问题时,你的脚本应该说明原因。

不要让 Bash 神秘地失败,而是这样做:

bash
command || {
  echo "❌ Failed to run command"
  exit 1
}

或者更好的做法,将其包装在函数中:

bash
die() {
  echo "Error: $1" >&2
  exit 1
}

现在你的脚本不仅会失败——它们还会沟通。未来的你会感谢现在的你提供的这种清晰度。

使用函数(是的,即使在小脚本中)

许多开发者避免在 Bash 中使用函数,认为这太过了。

其实不然。

函数让你能够:

  • 避免重复
  • 封装逻辑
  • 使脚本从上到下可读

示例:

bash
cleanup() {
  rm -rf /tmp/my_app
}

你不需要面向对象的 Bash。你只需要结构。函数是最简单的胜利。

像专业人士一样捕获信号

你是否曾在按下 Ctrl+C 后,脚本留下了半成品文件?

那是因为你没有捕获信号。

bash
trap cleanup EXIT INT TERM

这确保即使脚本意外退出,清理逻辑也会运行。

信号捕获对以下场景至关重要:

  • 临时文件
  • 锁文件
  • 后台进程

它们将脚本从"希望不出错"转变为"为混乱做好准备"。

像工作取决于此一样引用变量

在 Bash 中,未引用的变量就像地雷。

不好的做法:

bash
rm $file

好的做法:

bash
rm "$file"

如果 $file 包含空格、通配符或为空,未引用的变量可能导致数据丢失。

一个好的经验法则:如果是变量,就引用它。虽然有例外——但初学者不应该依赖它们。

这个单一习惯可以防止一些可以想象到的最糟糕的 shell bug。

使用数组而不是空格分隔的字符串

Bash 支持数组。使用它们。

不要这样:

bash
files="a.txt b.txt c.txt"

而是这样:

bash
files=("a.txt" "b.txt" "c.txt")

数组保留结构,安全处理空格,并且行为可预测。

循环变得更安全:

bash
for file in "${files[@]}"; do
  echo "$file"
done

一旦你正确使用数组,你就再也不想回去了。

以正确的方式逐行读取文件

这是一个经典陷阱。

错误做法:

bash
for line in $(cat file.txt); do

正确做法:

bash
while IFS= read -r line; do
  echo "$line"
done < file.txt

正确的方法:

  • 保留空白字符
  • 不会在特殊字符处中断
  • 高效处理大文件

它看起来冗长,但这是唯一安全的方式。

使用 set -x 像外科医生一样调试

当脚本行为异常时,猜测没有帮助。

打开执行跟踪:

bash
set -x

Bash 会在运行每个命令之前打印它。这对以下情况非常有价值:

  • CI 失败
  • 意外的变量值
  • 逻辑错误

你甚至可以临时启用它:

bash
set -x
# debug section
set +x

这是 Bash 的内置调试器。使用它。

优先使用 [[ ... ]] 而不是 [ ... ]

旧式测试表达式很脆弱。

使用:

bash
if [[ "$a" == "$b" ]]; then

而不是:

bash
if [ "$a" = "$b" ]; then

为什么?

  • 没有单词分割
  • 更安全的字符串比较
  • 支持正则表达式
  • 更少的引用麻烦

[[ ... ]] 是 Bash 最好的升级之一。充分利用它。

使用 Here-Docs 实现整洁的多行输入

当脚本开始嵌入 SQL、配置文件或大型文本块时,可读性会受损。

Here-docs 可以解决这个问题:

bash
cat <<EOF > config.yaml
port: 8080
env: production
EOF

它们非常适合:

  • 模板
  • Docker 配置
  • 内联文档

可读的 Bash 就是可维护的 Bash。

让脚本自文档化

添加 --help 标志。

认真的。

bash
if [[ "$1" == "--help" ]]; then
  echo "Usage: script.sh [options]"
  exit 0
fi

即使是简短的使用说明也能极大提高可用性——对队友和未来的你都是如此。

专业的脚本会自我解释。

像对待真正的软件一样对待 Bash 脚本

这是最大的技巧。

大多数 Bash 脚本失败不是因为 Bash 不好——而是因为我们把脚本当作一次性代码。

做这些事情:

  • 使用版本控制
  • 在意图不明显的地方添加注释
  • 当脚本增长时重构
  • 在干净的环境中测试

Bash 奖励纪律。忽视它,它会反咬你一口。

结语

Bash 脚本不是关于成为终端高手。Bash 脚本是关于让你的工作生活无摩擦。通过 Slack 发送消息。将随机笑话下载到你的消息中。找到随机图片包含在你的消息中。

你不必成为 Bash 所有方面的专家。你只需要一些好习惯和运用它们的信心。

终端是命令执行的地方,但它也是杠杆所在的地方。

本作品采用《CC 协议》,转载必须注明作者和本文链接