创建可复用的Bash脚本模板以提高效率
构建可复用的Bash脚本模板,包含严格模式、使用说明、日志记录、清理机制以及安全的getopts参数解析。
创建可复用的Bash脚本模板以提高效率
可复用的Bash脚本模板能帮助你在每次自动化任务时,避免重复编写相同的安全检查。一个好的模板能为脚本提供严格的错误处理、可预测的日志记录、使用帮助、参数解析以及清理钩子,然后再添加项目特定的逻辑。
目标不是构建一个庞大的框架,而是一个小巧的起点,让日常脚本保持一致且更易于调试。
为什么使用脚本模板?
当你的团队编写大量用于备份、部署、报告、日志清理或数据迁移的小脚本时,模板非常有用。如果没有模板,每个脚本处理错误、选项和日志的方式往往各不相同。
一个可复用的模板能为你提供:
- 一致的严格模式和引用习惯。
- 标准的
usage函数。 - 统一的日志辅助函数。
- 用于临时文件和锁的清理钩子。
- 使用
getopts进行可预测的命令行解析。
核心模板组件
从Bash本身开始,然后开启严格行为:
#!/usr/bin/env bash
set -euo pipefail
set -e 会在许多未处理的命令失败时退出,set -u 将未设置的变量视为错误,set -o pipefail 能捕获管道中的失败。你仍然需要对预期中的失败进行显式检查,但严格模式能捕获许多意外错误。
添加脚本名称和简短的使用说明块:
readonly SCRIPT_NAME="$(basename "$0")"
usage() {
cat <<USAGE
用法: $SCRIPT_NAME [-v] [-o output_dir] input_file
选项:
-v 启用详细日志
-o output_dir 将输出写入此目录
-h 显示此帮助信息
USAGE
}
使用小型日志辅助函数,而不是散落的echo调用:
log_info() {
[[ "$VERBOSE" -eq 1 ]] && printf '[INFO] %s\n' "$1"
}
die() {
printf '[ERROR] %s\n' "$1" >&2
exit 1
}
如果脚本创建临时文件或锁文件,请尽早添加清理函数:
cleanup() {
# 在此处删除临时文件或释放锁。
:
}
trap cleanup EXIT
使用getopts进行安全的参数解析
大多数可复用模板需要标志。Bash内置的getopts足以处理像-v和-o output_dir这样的短选项。
VERBOSE=0
OUTPUT_DIR="."
while getopts ":vo:h" opt; do
case "$opt" in
v) VERBOSE=1 ;;
o) OUTPUT_DIR=$OPTARG ;;
h) usage; exit 0 ;;
:) die "选项 -$OPTARG 需要参数" ;;
\?) die "未知选项: -$OPTARG" ;;
esac
done
shift "$((OPTIND - 1))"
INPUT_FILE=${1:-}
[[ -n "$INPUT_FILE" ]] || { usage >&2; exit 1; }
[[ -f "$INPUT_FILE" ]] || die "未找到输入文件: $INPUT_FILE"
":vo:h" 开头的冒号让脚本自行处理缺少选项参数的情况。解析后,shift "$((OPTIND - 1))" 移除已解析的选项,使位置参数更易读取。
一个可复用的紧凑模板
以下是一个适用于小型操作脚本的实用起点:
#!/usr/bin/env bash
set -euo pipefail
readonly SCRIPT_NAME="$(basename "$0")"
VERBOSE=0
OUTPUT_DIR="."
usage() {
cat <<USAGE
用法: $SCRIPT_NAME [-v] [-o output_dir] input_file
USAGE
}
log_info() {
[[ "$VERBOSE" -eq 1 ]] && printf '[INFO] %s\n' "$1"
}
die() {
printf '[ERROR] %s\n' "$1" >&2
exit 1
}
cleanup() {
:
}
trap cleanup EXIT
while getopts ":vo:h" opt; do
case "$opt" in
v) VERBOSE=1 ;;
o) OUTPUT_DIR=$OPTARG ;;
h) usage; exit 0 ;;
:) die "选项 -$OPTARG 需要参数" ;;
\?) die "未知选项: -$OPTARG" ;;
esac
done
shift "$((OPTIND - 1))"
INPUT_FILE=${1:-}
[[ -n "$INPUT_FILE" ]] || { usage >&2; exit 1; }
[[ -f "$INPUT_FILE" ]] || die "未找到输入文件: $INPUT_FILE"
mkdir -p "$OUTPUT_DIR"
log_info "正在处理 $INPUT_FILE"
# 在此处添加你的脚本逻辑。
保持模板简短。只有当多个脚本确实需要时,才添加共享函数。模板应该消除重复的设置工作,而不是让每个脚本都感觉像是一个框架。