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 | 一般错误 |
2 | Shell 内置命令的误用 |
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