Bash 脚本生成器
概述
这个技能提供了一个全面的工作流程,用于生成遵循当前标准和约定的最佳实践 bash 脚本。使用这个技能来生成系统管理、文本处理、API 客户端、自动化工作流等的脚本,内置了健壮的错误处理、日志记录、参数解析和验证功能。
何时使用这个技能
在以下情况下调用这个技能:
- 从头开始创建新的 bash 脚本
- 实施 shell 自动化或系统管理任务
- 构建命令行工具和实用程序
- 创建文本处理工作流(日志分析、数据转换等)
- 将手动命令序列转换为可重用的脚本
- 实施部署或构建自动化脚本
- 创建 cron 作业或计划任务
- 用户要求“创建”、“生成”、“构建”或“编写”一个 bash 脚本
- 实施使用 grep、awk、sed 或其他文本处理工具的脚本
强制步骤(不要跳过)
以下步骤是每次脚本生成的必需步骤。跳过这些步骤将导致脚本无法满足用户需求或无法通过验证。
强制:生成前需求
在生成任何脚本之前,必须完成以下步骤:
1. 与用户澄清需求(必需)
如果以下任何内容不清晰或未指定,请使用 AskUserQuestion 工具:
| 不明确 | 要问的问题 |
|---|---|
| 日志/数据格式未知 | “输入数据的格式是什么?(例如:nginx 组合日志、JSON、CSV、自定义)” |
| 大文件处理 | “这个流程会处理大文件(>100MB)吗?我们是否应该优化内存/性能?” |
| 错误处理偏好 | “应该如何处理错误?(快速失败、继续警告、重试)” |
| 安全上下文 | “这个脚本将处理敏感数据或以提升的权限运行吗?” |
| 可移植性需求 | “这个需要在不同的系统上运行吗?(bash 特定 vs POSIX sh)” |
| 输出格式不清晰 | “输出应该是什么格式?(人类可读、JSON、CSV 等)” |
不要跳过这一步。 假设会导致脚本无法满足用户需求。
2. 向用户解释您的方案(必需)
在编写代码之前,向用户解释:
- 脚本架构:您将创建哪些组件和函数
- 工具选择:为什么选择 grep/awk/sed 等特定任务
- 参考:
docs/text-processing-guide.md工具选择理由
- 参考:
- 关键设计决策:您所做的任何权衡或假设
- 定制点:用户可能想要修改的地方
生成前方案示例:
我将创建一个具有以下组件的日志分析器:
**架构:**
- 带有参数解析的主函数(getopts 模式)
- 4个分析函数:analyze_ips(),analyze_status_codes() 等
- 日志函数用于 INFO/DEBUG/ERROR 输出
- 清理陷阱用于信号处理
**工具选择:**
- 使用 awk 进行状态码分析(单次传递计数,如
docs/text-processing-guide.md 中推荐)
- 使用 grep 进行日期过滤(简单模式匹配)
- 使用 sort | uniq -c 进行频率计数
**定制点:**
- LOG_FORMAT 变量用于不同的 nginx 配置
- TOP_N 常量用于显示结果的数量
我是否可以按照这个设计进行?
3. 考虑使用模板(推荐)
何时使用模板:
- 使用模板 对于具有典型结构的标准脚本快速启动(CLI 工具、自动化脚本)
- 手动生成 对于具有独特要求或非标准架构的高度定制脚本更好
对于标准脚本,调用模板生成器:
bash scripts/generate_script_template.sh standard output-script.sh
这确保了一致的结构,所有必需的组件都预配置好了。模板包括:
- 适当的 shebang 和严格模式
- 日志函数(debug, info, warn, error)
- 错误处理(die, check_command, validate_file)
- 参数解析样板
- 清理陷阱处理程序
然后根据您的具体用例定制生成的模板。
脚本生成工作流程
生成 bash 脚本时,请遵循此工作流程。根据用户需求进行调整:
第一阶段:理解需求
收集有关脚本需要做什么的信息:
-
脚本目的:
- 它解决什么问题?
- 它自动化哪些任务?
- 谁将使用它(开发人员、运维、cron、CI/CD)?
-
功能需求:
- 输入源(文件、stdin、参数、API)
- 处理步骤(文本操作、系统操作等)
- 输出目标(stdout、文件、日志、API)
- 预期的数据格式
-
Shell 类型:
- 特定于 bash(现代系统,可以使用数组、关联数组等)
- POSIX sh(最大可移植性,功能有限)
- 默认为 bash,除非明确需要可移植性
-
参数解析:
- 需要的命令行选项
- 必需与可选参数
- 帮助/使用文本要求
-
错误处理需求:
- 应该如何处理错误?(快速失败、重试、优雅降级)
- 需要哪些日志级别?
- 是否需要退出代码?
-
性能考虑:
- 大文件处理需求
- 并行处理需求
- 资源限制
-
安全需求:
- 输入验证需求
- 凭据处理
- 权限要求
如果信息缺失或不清晰,请使用 AskUserQuestion。
第二阶段:架构规划
根据需求规划脚本结构:
-
确定脚本组件:
- 需要的函数
- 配置管理方法
- 日志策略
- 错误处理方法
-
选择合适的工具:
- grep 用于模式匹配和过滤
- awk 用于结构化文本处理(CSV、日志、列数据)
- sed 用于流编辑和替换
- find 用于文件系统操作
- curl/wget 用于 HTTP 操作
- 尽可能使用内置的 bash 功能
-
计划错误处理:
- 使用
set -eu pipefail进行严格模式(推荐) - 定义错误处理函数
- 计划清理程序(trap 用于 EXIT、ERR 信号)
- 使用
-
计划日志记录:
- 需要的日志级别(DEBUG, INFO, WARN, ERROR)
- 输出目标(stderr 用于日志,stdout 用于数据)
- 日志格式化
第三阶段:生成脚本结构
创建基本的脚本结构:
- Shebang 和标题:
#!/usr/bin/env bash
#
# 脚本名称:script-name.sh
# 描述:脚本功能的简要描述
# 作者:你的名字
# 创建日期:YYYY-MM-DD
#
- 严格模式(推荐所有脚本使用):
set -eu pipefail
IFS=$'
\t'
解释:
set -e:错误时退出set -u:未定义变量时退出set -o pipefail:管道中的任何命令失败时退出IFS:设置安全的内部字段分隔符
- 脚本级变量和常量:
# 脚本目录和名称
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
# 其他常量
readonly DEFAULT_CONFIG_FILE="${SCRIPT_DIR}/config.conf"
readonly LOG_FILE="/var/log/myscript.log"
- 信号处理程序用于清理:
# 清理函数
cleanup() {
local exit_code=$?
# 在这里添加清理逻辑
# 删除临时文件、释放锁等。
exit "${exit_code}"
}
# 设置清理陷阱
trap cleanup EXIT ERR INT TERM
第四阶段:生成核心函数
根据需求生成基本函数:
日志函数
# 日志函数
log_debug() {
if [[ "${LOG_LEVEL:-INFO}" == "DEBUG" ]]; then
echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2
fi
}
log_info() {
echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2
}
log_warn() {
echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2
}
log_error() {
echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2
}
log_fatal() {
echo "[FATAL] $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2
exit 1
}
错误处理函数
# 错误处理
die() {
log_error "$@"
exit 1
}
# 检查命令是否存在
check_command() {
local cmd="$1"
if ! command -v "${cmd}" &> /dev/null; then
die "Required command '${cmd}' not found. Please install it and try again."
fi
}
# 验证文件存在且可读
validate_file() {
local file="$1"
[[ -f "${file}" ]] || die "File not found: ${file}"
[[ -r "${file}" ]] || die "File not readable: ${file}"
}
参数解析函数
使用 getopts 进行简单选项:
# 解析命令行参数
parse_args() {
while getopts ":hvf:o:d" opt; do
case ${opt} in
h )
usage
exit 0
;;
v )
VERBOSE=true
;;
f )
INPUT_FILE="${OPTARG}"
;;
o )
OUTPUT_FILE="${OPTARG}"
;;
d )
LOG_LEVEL="DEBUG"
;;
\? )
echo "Invalid option: -${OPTARG}" >&2
usage
exit 1
;;
: )
echo "Option -${OPTARG} requires an argument" >&2
usage
exit 1
;;
esac
done
shift $((OPTIND -1))
}
使用/帮助函数
# 显示使用信息
usage() {
cat << EOF
Usage: ${SCRIPT_NAME} [OPTIONS] [ARGUMENTS]
Description:
简要描述脚本的功能
Options:
-h Show this help message and exit
-v Enable verbose output
-f FILE Input file path
-o FILE Output file path
-d Enable debug logging
Examples:
${SCRIPT_NAME} -f input.txt -o output.txt
${SCRIPT_NAME} -v -f data.log
EOF
}
第五阶段:生成业务逻辑
根据需求实现核心功能:
-
对于文本处理任务,使用适当的工具:
- grep:模式匹配、行过滤
- awk:字段提取、计算、格式化输出
- sed:流编辑、替换、删除
-
对于系统管理,包括:
- 验证先决条件
- 备份程序
- 回滚能力
- 进度指示器
-
对于 API 客户端,包括:
- HTTP 错误处理
- 重试逻辑
- 认证处理
- 响应解析
第六阶段:生成主函数
创建主执行流程:
# 主函数
main() {
# 解析参数
parse_args "$@"
# 验证先决条件
check_command "grep"
check_command "awk"
# 验证输入
[[ -n "${INPUT_FILE:-}" ]] || die "Input file not specified. Use -f option."
validate_file "${INPUT_FILE}"
log_info "Starting processing..."
# 主逻辑在这里
# ...
log_info "Processing completed successfully"
}
# 执行主函数
main "$@"
第七阶段:添加文档和注释
添加全面的注释:
- 函数文档:
#######################################
# 简要描述函数的功能
# 全局变量:
# VARIABLE_NAME
# 参数:
# $1 - 第一个参数的描述
# $2 - 第二个参数的描述
# 输出:
# 将结果写入 stdout
# 返回:
# 成功返回 0,错误返回非零
#######################################
function_name() {
# 实现
}
- 复杂逻辑的内联注释
- 在标题或使用函数中提供使用示例
第八阶段:验证生成的脚本
始终验证生成的脚本 使用 devops-skills:bash-script-validator 技能:
步骤:
1. 生成 bash 脚本
2. 使用脚本文件调用 devops-skills:bash-script-validator 技能
3. 查看验证结果
4. 修复任何识别出的问题(语法、安全性、最佳实践、可移植性)
5. 重新验证直到所有检查通过
6. 提供生成脚本和验证状态的摘要
验证清单:
- 语法正确(bash -n 通过)
- 处理 ShellCheck 警告
- 解决安全问题(没有命令注入、eval 变量等)
- 变量正确引用
- 实施错误处理
- 函数遵循单一责任原则
- 脚本遵循文档中的最佳实践
如果验证失败,修复问题并重新验证,直到所有检查通过。
文本处理工具选择指南
选择正确的工具来完成工作:
使用 grep 的时候:
- 在文件中搜索模式
- 过滤匹配/不匹配模式的行
- 计数匹配
- 简单行提取
示例:
# 在日志文件中查找错误行
grep "ERROR" application.log
# 查找不包含模式的行
grep -v "DEBUG" application.log
# 大小写不敏感搜索并带有行号
grep -in "warning" *.log
# 扩展正则表达式模式
grep -E "(error|fail|critical)" app.log
使用 awk 的时候:
- 处理结构化数据(CSV、TSV、具有字段的日志)
- 对数据执行计算
- 提取特定字段
- 生成格式化报告
- 复杂的条件逻辑
示例:
# 提取特定字段(例如,第 2 和第 4 列)
awk '{print $2, $4}' data.txt
# 列中值的总和
awk '{sum += $3} END {print sum}' numbers.txt
# 处理自定义分隔符的 CSV
awk -F',' '{print $1, $3}' data.csv
# 条件处理
awk '$3 > 100 {print $1, $3}' data.txt
# 格式化输出
awk '{printf "Name: %-20s Age: %d
", $1, $2}' people.txt
使用 sed 的时候:
- 执行替换
- 删除匹配模式的行
- 就地文件编辑
- 流编辑
- 简单的转换
示例:
# 简单替换(第一次出现)
sed 's/old/new/' file.txt
# 全局替换(所有出现)
sed 's/old/new/g' file.txt
# 就地编辑
sed -i 's/old/new/g' file.txt
# 删除匹配模式的行
sed '/pattern/d' file.txt
# 仅替换匹配模式的行
sed '/ERROR/s/old/new/g' log.txt
# 多个命令
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt
在管道中组合工具:
# grep 过滤,awk 提取
grep "ERROR" app.log | awk '{print $1, $5}'
# sed 清理,awk 处理
sed 's/[^[:print:]]//g' data.txt | awk '{sum += $2} END {print sum}'
# 多个阶段
cat access.log \
| grep "GET" \
| sed 's/.*HTTP\/[0-9.]*" //' \
| awk '$1 >= 200 && $1 < 300 {count++} END {print count}'
生成脚本的最佳实践
安全
- 始终引用变量:
# 好的
rm "${file}"
grep "${pattern}" "${input_file}"
# 坏的 - 容易单词分割和 globbing
rm $file
grep $pattern $input_file
- 验证所有输入:
# 验证文件路径
[[ "${input_file}" =~ ^[a-zA-Z0-9/_.-]+$ ]] || die "Invalid file path"
# 验证数字输入
[[ "${count}" =~ ^[0-9]+$ ]] || die "Count must be numeric"
- 避免使用 eval 和用户输入:
# 永远不要这样做
eval "${user_input}"
# 相反,使用 case 语句或验证过的输入
case "${command}" in
start) do_start ;;
stop) do_stop ;;
*) die "Invalid command" ;;
esac
- 使用 $() 而不是反引号:
# 好的 - 更易读,可以嵌套
result=$(command)
outer=$(inner $(another_command))
# 坏的 - 难以阅读,不能嵌套
result=`command`
性能
- 尽可能使用内置功能:
# 好的 - 使用 bash 内置
if [[ -f "${file}" ]]; then
# 慢 - 产生外部进程
if [ -f "${file}" ]; then
- 避免无用的 cat(UUOC):
# 好的
grep "pattern" file.txt
awk '{print $1}' file.txt
# 坏的 - 不必要的 cat
cat file.txt | grep "pattern"
cat file.txt | awk '{print $1}'
- 尽可能单次传递处理:
# 好的 - 单次 awk 调用
awk '/ERROR/ {errors++} /WARN/ {warns++} END {print errors, warns}' log.txt
# 效率较低 - 多个 greps
errors=$(grep -c "ERROR" log.txt)
warns=$(grep -c "WARN" log.txt)
可维护性
- 使用函数重用代码
- 保持函数专注(单一责任)
- 使用有意义的变量名
- 为复杂逻辑添加注释
- 将相关功能分组
- 使用 readonly 用于常量
可移植性(当目标是 POSIX sh)
- 避免 bash 特定功能:
# bash 特定(数组)
arr=(one two three)
# POSIX 替代品
set -- one two three
# bash 特定 ([[ ]])
if [[ -f "${file}" ]]; then
# POSIX 替代品
if [ -f "${file}" ]; then
- 用 sh 测试:
sh -n script.sh # 语法检查
常见脚本模式
模式 1:简单的命令行工具
#!/usr/bin/env bash
set -eu pipefail
usage() {
cat << EOF
Usage: ${0##*/} [OPTIONS] FILE
Process FILE and output results.
Options:
-h Show this help
-v Verbose output
-o FILE Output file (default: stdout)
EOF
}
main() {
local verbose=false
local output_file=""
local input_file=""
while getopts ":hvo:" opt; do
case ${opt} in
h) usage; exit 0 ;;
v) verbose=true ;;
o) output_file="${OPTARG}" ;;
*) echo "Invalid option: -${OPTARG}" >&2; usage; exit 1 ;;
esac
done
shift $((OPTIND - 1))
input_file="${1:-}"
[[ -n "${input_file}" ]] || { echo "Error: FILE required" >&2; usage; exit 1; }
[[ -f "${input_file}" ]] || { echo "Error: File not found: ${input_file}" >&2; exit 1; }
# Process file
if [[ -n "${output_file}" ]]; then
process_file "${input_file}" > "${output_file}"
else
process_file "${input_file}"
fi
}
process_file() {
local file="$1"
# Processing logic here
cat "${file}"
}
main "$@"
模式 2:文本处理脚本
#!/usr/bin/env bash
set -eu pipefail
# Process log file: extract errors, count by type
process_log() {
local log_file="$1"
echo "Error Summary:"
echo "=============="
# Extract errors and count by type
grep "ERROR" "${log_file}" \
| sed 's/.*ERROR: //' \
| sed 's/ -.*//' \
| sort \
| uniq -c \
| sort -rn \
| awk '{printf " %-30s %d
", $2, $1}'
echo ""
echo "Total errors: $(grep -c "ERROR" "${log_file}")"
}
main() {
[[ $# -eq 1 ]] || { echo "Usage: $0 LOG_FILE" >&2; exit 1; }
[[ -f "$1" ]] || { echo "Error: File not found: $1" >&2; exit 1; }
process_log "$1"
}
main "$@"
模式 3:批量处理与并行执行
#!/usr/bin/env bash
set -eu pipefail
# Process a single file
process_file() {
local file="$1"
local output="${file}.processed"
# Processing logic
sed 's/old/new/g' "${file}" > "${output}"
echo "Processed: ${file} -> ${output}"
}
# Export function for parallel execution
export -f process_file
main() {
local input_dir="${1:-.}"
local max_jobs="${2:-4}"
# Find all files and process in parallel
find "${input_dir}" -type f -name "*.txt" -print0 \
| xargs -0 -P "${max_jobs}" -I {} bash -c 'process_file "$@"' _ {}
}
main "$@"
辅助脚本
scripts/ 目录包含辅助工具,用于协助生成:
generate_script_template.sh
从标准模板生成 bash 脚本,具有适当的结构、错误处理和日志记录。
用法:
bash scripts/generate_script_template.sh standard [SCRIPT_NAME]
示例:
bash scripts/generate_script_template.sh standard myscript.sh
脚本将复制标准模板并使其可执行。然后您可以根据特定需求进行定制。
文档资源
核心 Bash 脚本
docs/bash-scripting-guide.md
- 全面的 bash 脚本指南
- Bash vs POSIX sh 差异
- 严格模式和错误处理策略
- 函数、作用域和变量处理
- 数组和关联数组
- 参数扩展技术
- 进程替换和命令替换
- 最佳实践和现代模式
docs/script-patterns.md
- 常见的 bash 脚本模式和模板
- 参数解析模式(getopts, manual)
- 配置文件处理
- 日志框架和方法
- 并行处理模式
- 锁文件管理
- 信号处理和清理
- 重试逻辑和退避策略
docs/generation-best-practices.md
- 生成高质量脚本的指南
- 代码组织原则
- 命名约定
- 文档标准
- 测试 bash 脚本的方法
- 可移植性考虑
- 安全最佳实践
- 性能优化技术
文本处理工具
docs/text-processing-guide.md
- 何时使用 grep vs awk vs sed
- 在管道中有效组合工具
- 大文件的性能优化
- 常见的文本处理模式
- 真实世界的示例和用例
特定工具参考
注意: 以下参考包含在 devops-skills:bash-script-validator 技能中,并由这个技能引用:
- bash-reference.md - Bash 特性和语法
- grep-reference.md - grep 模式和用法
- awk-reference.md - AWK 文本处理
- sed-reference.md - sed 流编辑
- regex-reference.md - 正则表达式(BRE vs ERE)
示例脚本
位于 examples/ 目录:
log-analyzer.sh
演示 grep、awk 和 sed 的使用,用于日志文件分析。显示模式匹配、字段提取和统计分析。此示例说明:
- 使用 grep 过滤日志条目
- 使用 awk 进行字段提取和格式化
- 使用 sed 进行文本转换
- 生成摘要报告并正确处理错误
模板
位于 assets/templates/ 目录:
standard-template.sh
具有全面功能的即用型模板:
- 适当的 shebang(
#!/usr/bin/env bash)和严格模式 - 日志函数(debug, info, warn, error)
- 错误处理(die, check_command, validate_file)
- 使用 getopts 进行参数解析
- 清理陷阱处理程序
- 使用文档
使用此模板作为起点,并根据特定需求进行定制。
与 devops-skills:bash-script-validator 的集成
生成任何 bash 脚本后,自动调用 devops-skills:bash-script-validator 技能 以确保质量:
步骤:
1. 按照上述工作流程生成 bash 脚本
2. 使用脚本文件调用 devops-skills:bash-script-validator 技能
3. 查看验证结果(语法、ShellCheck、安全性、性能)
4. 修复任何识别出的问题
5. 重新验证直到所有检查通过
6. 提供生成脚本和验证状态的摘要
这确保所有生成的脚本:
- 具有正确的语法
- 遵循 bash 最佳实践
- 避免常见的安全问题
- 针对性能进行优化
- 包括适当的错误处理
- 有适当的文档记录
沟通指南(必需)
这些不是可选的。 每次脚本生成都遵循这些指南:
生成前(见上面的“强制:生成前需求”)
- ✅ 使用 AskUserQuestion 提出澄清问题
- ✅ 解释您的方案并获得用户确认
- ✅ 考虑使用标准模板
生成期间(必需)
您必须明确引用文档 当使用模式或进行工具选择时。这有助于用户理解基本原理并学习最佳实践。
-
在方案解释中,引用文档:
- 工具选择理由:“使用 awk 进行字段提取(推荐在
docs/text-processing-guide.md中用于结构化数据)” - 模式选择:“使用 getopts 模式来自
docs/script-patterns.md” - 最佳实践:“遵循
docs/bash-scripting-guide.md中的严格模式指南”
- 工具选择理由:“使用 awk 进行字段提取(推荐在
-
在生成的代码注释中,参考文档:
# 使用单次传递 awk 处理(根据 docs/text-processing-guide.md) awk '{ip[$1]++} END {for (i in ip) print ip[i], i}' "${log_file}" -
最低引用要求:至少有 2 个文档引用出现在:
- 方案解释(代码生成前)
- 后生成摘要
生成后(必需)
提供 后生成摘要,包括:
## 生成脚本摘要
**文件:** path/to/script.sh
**架构:**
- [列出主要函数及其用途]
**工具选择:**
- grep:[为什么使用]
- awk:[为什么使用]
- sed:[为什么使用,或“不需要”]
**关键特性:**
- [特性 1]
- [特性 2]
**定制点:**
- `VARIABLE_NAME`:[更改什么]
- `function_name()`:[何时修改]
**使用示例:**
```bash
./script.sh --help
./script.sh -v input.log
./script.sh -o report.txt input.log
验证状态: ✅ 通过 ShellCheck / ❌ 问题发现(修复中…)
文档参考:
- docs/text-processing-guide.md(工具选择)
- docs/script-patterns.md(参数解析)
这个摘要确保用户了解生成的内容以及如何使用它。
## 资源
### 官方文档
- [GNU Bash 手册](https://www.gnu.org/software/bash/manual/bash.html)
- [GNU grep 手册](https://www.gnu.org/software/grep/manual/grep.html)
- [GNU awk 手册](https://www.gnu.org/software/gawk/manual/gawk.html)
- [GNU sed 手册](https://www.gnu.org/software/sed/manual/sed.html)
- [POSIX Shell 规范](https://pubs.opengroup.org/onlinepubs/9699919799/)
- [ShellCheck](https://www.shellcheck.net/)
### 最佳实践指南
- [Google Shell 风格指南](https://google.github.io/styleguide/shellguide.html)
- [Bash 最佳实践](https://bertvv.github.io/cheat-sheets/Bash.html)
- [最小安全 Bash 脚本模板](https://betterdev.blog/minimal-safe-bash-script-template/)
### 内部参考
所有文档都包含在 `docs/` 目录中,用于离线参考和上下文加载。
---
**注意**:这个技能自动使用 devops-skills:bash-script-validator 技能验证生成的脚本,为 Claude 提供全面的反馈,以确保高质量的、即用型的 bash 脚本。