Skip to content

1. 内置工具

1.1 set

set -e:当命令失败时停止脚本

set -u:当使用未设置的变量时退出

set -o pipefail:确保检测到管道失败

比如:

bash
set -euo pipefail

output=$(cat /nonexistent/file)
echo "如果文件不存在,这行不会执行。"
set -euo pipefail

output=$(cat /nonexistent/file)
echo "如果文件不存在,这行不会执行。"

1.2 trap

trap 允许你捕获信号和错误,从而进行清理或优雅退出

比如:

bash
trap 'rm -f /tmp/tempfile' EXIT

echo "Working..." > /tmp/tempfile
trap 'rm -f /tmp/tempfile' EXIT

echo "Working..." > /tmp/tempfile

1.3 exit

2. 静默

默认情况下,Bash 脚本在发生错误时仍会继续运行。这可能导致严重后果

bash
rm /critical/file || echo "Error: Could not delete file"
rm /critical/file || echo "Error: Could not delete file"

在此示例中,脚本将记录错误消息,但会继续执行后续命令,可能导致损坏

3. 如何检查错误

每个 Bash 命令都会返回一个退出代码

  • 退出代码 0:表示成功。
  • 非零退出代码:表示失败。

常见代码包括:

代码说明
0成功
1一般错误
2Shell 内置命令的误用
127命令未找到
128无效的退出参数
130脚本被 Ctrl+C 终止

4. 高级调试

4.1 set -x

4.2 bashdb

bashdb 是 Bash 脚本的调试器,提供断点和逐步执行功能

4.3 strace

strace 捕获脚本进行的系统调用,有助于诊断 I/O 错误

5. 案例

5.1 没有设置变量

验证变量确保在使用变量之前定义它们。

添加 trap 以确保安全使用 trap 拦截错误并停止执行。

试运行测试在运行实际命令之前,加入试运行模式以测试脚本。

bash
#!/bin/bash

set -euo pipefail
trap'echo "An error occurred. Exiting."; exit 1' ERR

# 确保目标目录已定义
if [[ -z "${TARGET_DIR:-}" ]]; then
echo"Error: TARGET_DIR is not defined."
exit 1
fi

# 试运行模式以确保安全
if [[ "${DRY_RUN:-false}" == "true" ]]; then
echo"Dry run: Listing files to delete in $TARGET_DIR"
  ls "$TARGET_DIR"
else
echo"Deleting files in $TARGET_DIR..."
  rm -rf "$TARGET_DIR"/*
fi
#!/bin/bash

set -euo pipefail
trap'echo "An error occurred. Exiting."; exit 1' ERR

# 确保目标目录已定义
if [[ -z "${TARGET_DIR:-}" ]]; then
echo"Error: TARGET_DIR is not defined."
exit 1
fi

# 试运行模式以确保安全
if [[ "${DRY_RUN:-false}" == "true" ]]; then
echo"Dry run: Listing files to delete in $TARGET_DIR"
  ls "$TARGET_DIR"
else
echo"Deleting files in $TARGET_DIR..."
  rm -rf "$TARGET_DIR"/*
fi

试运行

$ TARGET_DIR=/tmp DRY_RUN=true ./cleanup.sh
Dry run: Listing files to delete in /tmp
file1.txt
file2.log
tempfile
$ TARGET_DIR=/tmp DRY_RUN=true ./cleanup.sh
Dry run: Listing files to delete in /tmp
file1.txt
file2.log
tempfile

实际运行

bash
$ TARGET_DIR=/tmp DRY_RUN=false ./cleanup.sh
Deleting files in /tmp...
$ TARGET_DIR=/tmp DRY_RUN=false ./cleanup.sh
Deleting files in /tmp...

5.2 迁移数据库

检查文件是否存在在继续之前验证所需的 SQL 文件是否存在。

使用 trap 进行错误处理优雅地捕获和处理错误。

在迁移前备份数据库创建数据库备份以允许在失败时回滚。

bash
#!/bin/bash
set -euo pipefail
trap'echo "Migration failed. Restoring database backup..."; mysql -u user -p database < /backup/db_backup.sql' ERR

# 验证迁移文件
if [[ ! -f "migration.sql" ]]; then
echo"Error: migration.sql file not found."
exit 1
fi

# 备份数据库
echo"Creating database backup..."
mysqldump -u user -p database > /backup/db_backup.sql

# 应用迁移
echo"Applying migration..."
mysql -u user -p database < migration.sql
#!/bin/bash
set -euo pipefail
trap'echo "Migration failed. Restoring database backup..."; mysql -u user -p database < /backup/db_backup.sql' ERR

# 验证迁移文件
if [[ ! -f "migration.sql" ]]; then
echo"Error: migration.sql file not found."
exit 1
fi

# 备份数据库
echo"Creating database backup..."
mysqldump -u user -p database > /backup/db_backup.sql

# 应用迁移
echo"Applying migration..."
mysql -u user -p database < migration.sql