关于 shell-scripting
面向开发者和系统管理员的 Shell 脚本技能,涵盖 Bash 和 zsh 自动化、错误处理及命令行工具开发模式。
主要功能
- 01Bash 和 zsh 脚本模式
- 02错误处理与清理
- 03变量、数组和控制流
- 04输入输出与文本处理
- 05Shell 脚本实践建议
适用场景
- 01编写自动化和定时脚本
- 02构建命令行工具
- 03编写构建与部署脚本
- 04处理日志和批量文件
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ 89jobrien/ steve --skill shell-scripting安装后在 Claude Code 中输入/shell-scripting确认已加载。
详细介绍
Shell 脚本
全面介绍 Shell 脚本技能,涵盖 bash/zsh 模式、自动化、错误处理和 CLI 工具开发。
何时使用此技能
- 编写自动化脚本
- 创建 CLI 工具
- 执行系统管理任务
- 编写构建和部署脚本
- 处理和分析日志
- 操作文件并执行批量任务
- 设置 cron 作业和定时任务
脚本结构
模板
#!/usr/bin/env bash
# Script: name.sh
# Description: What this script does
# Usage: ./name.sh [options] <args>
set -euo pipefail # Exit on error, undefined vars, pipe failures
IFS=$'\n\t' # Safer word splitting
# Constants
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
# Default values
VERBOSE=false
DRY_RUN=false
# Functions
usage() {
cat <<EOF
Usage: $SCRIPT_NAME [options] <argument>
Options:
-h, --help Show this help message
-v, --verbose Enable verbose output
-n, --dry-run Show what would be done
EOF
}
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2
}
error() {
log "ERROR: $*"
exit 1
}
# Main logic
main() {
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
-v|--verbose)
VERBOSE=true
shift
;;
-n|--dry-run)
DRY_RUN=true
shift
;;
*)
break
;;
esac
done
# Your logic here
}
main "$@"
错误处理
设置选项
set -e # Exit on any error
set -u # Error on undefined variables
set -o pipefail # Pipe failure is script failure
set -x # Debug: print each command (use sparingly)
使用 Trap 执行清理
cleanup() {
rm -f "$TEMP_FILE"
log "Cleanup complete"
}
trap cleanup EXIT
# Also handle specific signals
trap 'error "Script interrupted"' INT TERM
错误检查模式
# Check command exists
command -v jq >/dev/null 2>&1 || error "jq is required but not installed"
# Check file exists
[[ -f "$FILE" ]] || error "File not found: $FILE"
# Check directory exists
[[ -d "$DIR" ]] || mkdir -p "$DIR"
# Check variable is set
[[ -n "${VAR:-}" ]] || error "VAR is not set"
# Check exit status explicitly
if ! some_command; then
error "some_command failed"
fi
变量与替换
变量展开
# Default values
${VAR:-default} # Use default if VAR is unset or empty
${VAR:=default} # Set VAR to default if unset or empty
${VAR:+value} # Use value if VAR is set
${VAR:?error msg} # Error if VAR is unset or empty
# String manipulation
${VAR#pattern} # Remove shortest prefix match
${VAR##pattern} # Remove longest prefix match
${VAR%pattern} # Remove shortest suffix match
${VAR%%pattern} # Remove longest suffix match
${VAR/old/new} # Replace first occurrence
${VAR//old/new} # Replace all occurrences
${#VAR} # Length of VAR
数组
# Declare array
declare -a ARRAY=("one" "two" "three")
# Access elements
echo "${ARRAY[0]}" # First element
echo "${ARRAY[@]}" # All elements
echo "${#ARRAY[@]}" # Number of elements
echo "${!ARRAY[@]}" # All indices
# Iterate
for item in "${ARRAY[@]}"; do
echo "$item"
done
# Append
ARRAY+=("four")
关联数组
declare -A MAP
MAP["key1"]="value1"
MAP["key2"]="value2"
# Access
echo "${MAP[key1]}"
# Check key exists
[[ -v MAP[key1] ]] && echo "key1 exists"
# Iterate
for key in "${!MAP[@]}"; do
echo "$key: ${MAP[$key]}"
done
控制流
条件语句
# String comparison
[[ "$str" == "value" ]]
[[ "$str" != "value" ]]
[[ -z "$str" ]] # Empty
[[ -n "$str" ]] # Not empty
# Numeric comparison
[[ "$num" -eq 5 ]] # Equal
[[ "$num" -ne 5 ]] # Not equal
[[ "$num" -lt 5 ]] # Less than
[[ "$num" -gt 5 ]] # Greater than
# File tests
[[ -f "$file" ]] # File exists
[[ -d "$dir" ]] # Directory exists
[[ -r "$file" ]] # Readable
[[ -w "$file" ]] # Writable
[[ -x "$file" ]] # Executable
# Logical operators
[[ "$a" && "$b" ]] # AND
[[ "$a" || "$b" ]] # OR
[[ ! "$a" ]] # NOT
循环
# For loop
for i in {1..10}; do
echo "$i"
done
# While loop
while read -r line; do
echo "$line"
done < "$file"
# Process substitution
while read -r line; do
echo "$line"
done < <(command)
# C-style for
for ((i=0; i<10; i++)); do
echo "$i"
done
输入/输出
读取输入
# Read from user
read -r -p "Enter name: " name
# Read password (hidden)
read -r -s -p "Password: " password
# Read with timeout
read -r -t 5 -p "Quick! " answer
# Read file line by line
while IFS= read -r line; do
echo "$line"
done < "$file"
输出与重定向
# Redirect stdout
command > file # Overwrite
command >> file # Append
# Redirect stderr
command 2> file
# Redirect both
command &> file
command > file 2>&1
# Discard output
command > /dev/null 2>&1
# Tee (output and save)
command | tee file
文本处理
常见模式
# Find and process files
find . -name "*.log" -exec grep "ERROR" {} +
# Process CSV
while IFS=, read -r col1 col2 col3; do
echo "$col1: $col2"
done < file.csv
# JSON processing (with jq)
jq '.key' file.json
jq -r '.items[]' file.json
# AWK one-liners
awk '{print $1}' file # First column
awk -F: '{print $1}' /etc/passwd # Custom delimiter
awk 'NR > 1' file # Skip header
# SED one-liners
sed 's/old/new/g' file # Replace all
sed -i 's/old/new/g' file # In-place edit
sed -n '10,20p' file # Print lines 10-20
最佳实践
应做事项
- 为所有变量展开加引号:
"$VAR" - 测试时优先使用
[[ ]],而非[ ] - 优先使用
$(command),而非反引号 - 检查返回值
- 对常量使用
readonly - 在函数中使用
local - 提供
--help选项 - 使用有意义的退出码
不应做事项
- 解析
ls的输出 - 对不可信输入使用
eval - 假设路径中不含空格
- 忽略 shellcheck 警告
- 编写一个庞大的脚本(应将其模块化)
参考文件
references/one_liners.md- 实用的单行命令
与其他技能的集成
- developer-experience - 用于工具自动化
- debugging - 用于脚本调试
- testing - 用于脚本测试模式
评论
支持 Markdown