引言

Shell脚本编程是Linux系统管理和自动化运维的核心技能。无论是简单的文件处理,还是复杂的系统监控,Shell脚本都能提供高效的解决方案。本文将通过丰富的实例和最佳实践,帮助读者从Shell脚本入门到精通,掌握自动化运维的精髓。

Shell基础语法

脚本结构和执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/bash
# 这是一个Shell脚本示例
# 文件名: hello.sh

# 设置脚本选项
set -e # 遇到错误立即退出
set -u # 使用未定义变量时报错
set -o pipefail # 管道中任何命令失败都会导致整个管道失败

# 脚本信息
SCRIPT_NAME=$(basename "$0")
SCRIPT_DIR=$(dirname "$0")
SCRIPT_PATH=$(readlink -f "$0")

echo "脚本名称: $SCRIPT_NAME"
echo "脚本目录: $SCRIPT_DIR"
echo "脚本路径: $SCRIPT_PATH"

# 基本输出
echo "Hello, World!"
printf "格式化输出: %s %d\n" "数字" 42

# 执行方式
# 1. bash hello.sh
# 2. chmod +x hello.sh && ./hello.sh
# 3. source hello.sh 或 . hello.sh

变量和数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/bin/bash
# 变量定义和使用

# 字符串变量
name="张三"
age=25
readonly PI=3.14159 # 只读变量

# 数组
fruits=("苹果" "香蕉" "橙子")
declare -A colors # 关联数组
colors["red"]="红色"
colors["blue"]="蓝色"

# 环境变量
export MY_VAR="全局变量"

# 特殊变量
echo "脚本名称: $0"
echo "第一个参数: $1"
echo "所有参数: $@"
echo "参数个数: $#"
echo "上个命令退出状态: $?"
echo "当前进程ID: $$"

# 变量操作
echo "姓名: $name"
echo "年龄: $age"
echo "字符串长度: ${#name}"
echo "数组长度: ${#fruits[@]}"
echo "数组元素: ${fruits[0]}"
echo "所有数组元素: ${fruits[@]}"

# 变量默认值
echo "用户名: ${USER:-默认用户}"
echo "配置文件: ${CONFIG_FILE:=/etc/default.conf}"

# 字符串操作
text="Hello World"
echo "转大写: ${text^^}"
echo "转小写: ${text,,}"
echo "替换: ${text/World/Shell}"
echo "截取: ${text:0:5}"

条件判断和控制结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#!/bin/bash
# 条件判断示例

# if-else语句
check_file() {
local file=$1

if [ -f "$file" ]; then
echo "文件 $file 存在"
if [ -r "$file" ]; then
echo "文件可读"
fi
if [ -w "$file" ]; then
echo "文件可写"
fi
if [ -x "$file" ]; then
echo "文件可执行"
fi
elif [ -d "$file" ]; then
echo "$file 是目录"
else
echo "$file 不存在"
fi
}

# 数值比较
compare_numbers() {
local num1=$1
local num2=$2

if [ "$num1" -eq "$num2" ]; then
echo "$num1 等于 $num2"
elif [ "$num1" -gt "$num2" ]; then
echo "$num1 大于 $num2"
else
echo "$num1 小于 $num2"
fi
}

# 字符串比较
compare_strings() {
local str1=$1
local str2=$2

if [ "$str1" = "$str2" ]; then
echo "字符串相等"
elif [ "$str1" \< "$str2" ]; then
echo "$str1 在字典序中小于 $str2"
else
echo "$str1 在字典序中大于 $str2"
fi

# 模式匹配
case "$str1" in
*.txt)
echo "这是一个文本文件"
;;
*.log)
echo "这是一个日志文件"
;;
*)
echo "未知文件类型"
;;
esac
}

# 逻辑运算
logical_operations() {
local file=$1
local size_limit=1000000 # 1MB

# AND运算
if [ -f "$file" ] && [ -s "$file" ]; then
echo "文件存在且不为空"
fi

# OR运算
if [ ! -f "$file" ] || [ ! -r "$file" ]; then
echo "文件不存在或不可读"
return 1
fi

# 复杂条件
file_size=$(stat -c%s "$file" 2>/dev/null || echo 0)
if [ -f "$file" ] && [ "$file_size" -gt "$size_limit" ]; then
echo "文件过大: $(numfmt --to=iec $file_size)B"
fi
}

# 测试函数
test_conditions() {
echo "=== 文件检查测试 ==="
check_file "/etc/passwd"
check_file "/tmp"
check_file "/nonexistent"

echo -e "\n=== 数值比较测试 ==="
compare_numbers 10 20
compare_numbers 30 30
compare_numbers 50 40

echo -e "\n=== 字符串比较测试 ==="
compare_strings "apple" "banana"
compare_strings "test.txt" "example.log"
}

# 执行测试
test_conditions

循环结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/bin/bash
# 循环结构示例

# for循环 - 遍历列表
echo "=== for循环示例 ==="
fruits=("苹果" "香蕉" "橙子" "葡萄")

for fruit in "${fruits[@]}"; do
echo "水果: $fruit"
done

# for循环 - 数值范围
echo -e "\n=== 数值范围循环 ==="
for i in {1..5}; do
echo "数字: $i"
done

# for循环 - C风格
echo -e "\n=== C风格循环 ==="
for ((i=1; i<=3; i++)); do
echo "计数: $i"
done

# while循环
echo -e "\n=== while循环示例 ==="
counter=1
while [ $counter -le 3 ]; do
echo "while计数: $counter"
((counter++))
done

# until循环
echo -e "\n=== until循环示例 ==="
num=1
until [ $num -gt 3 ]; do
echo "until计数: $num"
((num++))
done

# 遍历文件
echo -e "\n=== 文件遍历示例 ==="
process_files() {
local directory=${1:-.}

# 遍历目录中的文件
for file in "$directory"/*; do
if [ -f "$file" ]; then
echo "处理文件: $(basename "$file")"
# 这里可以添加文件处理逻辑
fi
done
}

# 读取文件内容
echo -e "\n=== 读取文件示例 ==="
read_file_lines() {
local file=$1

if [ ! -f "$file" ]; then
echo "文件不存在: $file"
return 1
fi

local line_num=1
while IFS= read -r line; do
echo "第${line_num}行: $line"
((line_num++))
done < "$file"
}

# 无限循环示例
monitor_system() {
echo "开始系统监控 (按Ctrl+C停止)"

while true; do
clear
echo "=== 系统监控 $(date) ==="
echo "负载: $(uptime | awk -F'load average:' '{print $2}')"
echo "内存: $(free -h | grep Mem | awk '{print $3"/"$2}')"
echo "磁盘: $(df -h / | tail -1 | awk '{print $5}')"

sleep 5
done
}

# 循环控制
loop_control_demo() {
echo -e "\n=== 循环控制示例 ==="

for i in {1..10}; do
if [ $i -eq 3 ]; then
echo "跳过数字 $i"
continue
fi

if [ $i -eq 8 ]; then
echo "在数字 $i 处退出循环"
break
fi

echo "处理数字: $i"
done
}

# 嵌套循环
nested_loop_demo() {
echo -e "\n=== 嵌套循环示例 ==="

for i in {1..3}; do
echo "外层循环: $i"
for j in {a..c}; do
echo " 内层循环: $j"
done
done
}

# 执行示例
process_files "/tmp"
loop_control_demo
nested_loop_demo

# 如果需要测试文件读取,可以创建一个测试文件
echo -e "第一行\n第二行\n第三行" > /tmp/test.txt
read_file_lines "/tmp/test.txt"
rm -f /tmp/test.txt

函数和模块化

函数定义和使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#!/bin/bash
# 函数示例

# 基本函数定义
greet() {
echo "Hello, $1!"
}

# 带返回值的函数
add_numbers() {
local num1=$1
local num2=$2
local result=$((num1 + num2))
echo $result # 返回结果
}

# 复杂函数示例
backup_file() {
local source_file=$1
local backup_dir=${2:-/backup}
local timestamp=$(date +%Y%m%d_%H%M%S)

# 参数验证
if [ $# -lt 1 ]; then
echo "用法: backup_file <源文件> [备份目录]" >&2
return 1
fi

if [ ! -f "$source_file" ]; then
echo "错误: 源文件不存在: $source_file" >&2
return 1
fi

# 创建备份目录
mkdir -p "$backup_dir"

# 生成备份文件名
local filename=$(basename "$source_file")
local backup_file="$backup_dir/${filename}.${timestamp}.bak"

# 执行备份
if cp "$source_file" "$backup_file"; then
echo "备份成功: $backup_file"
return 0
else
echo "备份失败" >&2
return 1
fi
}

# 递归函数示例
factorial() {
local n=$1

if [ $n -le 1 ]; then
echo 1
else
local prev=$(factorial $((n-1)))
echo $((n * prev))
fi
}

# 数组处理函数
process_array() {
local -n arr_ref=$1 # 数组引用
local operation=$2

case "$operation" in
"sum")
local total=0
for num in "${arr_ref[@]}"; do
total=$((total + num))
done
echo $total
;;
"max")
local max=${arr_ref[0]}
for num in "${arr_ref[@]}"; do
if [ $num -gt $max ]; then
max=$num
fi
done
echo $max
;;
"sort")
# 冒泡排序
local len=${#arr_ref[@]}
for ((i=0; i<len-1; i++)); do
for ((j=0; j<len-i-1; j++)); do
if [ ${arr_ref[j]} -gt ${arr_ref[j+1]} ]; then
# 交换元素
local temp=${arr_ref[j]}
arr_ref[j]=${arr_ref[j+1]}
arr_ref[j+1]=$temp
fi
done
done
;;
esac
}

# 错误处理函数
handle_error() {
local exit_code=$1
local line_number=$2
local command=$3

echo "错误发生在第 $line_number 行" >&2
echo "命令: $command" >&2
echo "退出码: $exit_code" >&2

# 清理工作
cleanup

exit $exit_code
}

# 清理函数
cleanup() {
echo "执行清理工作..."
# 删除临时文件
rm -f /tmp/script_temp_*
# 恢复原始设置
# ...
}

# 日志函数
log() {
local level=$1
shift
local message="$@"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')

case "$level" in
"INFO")
echo "[$timestamp] [INFO] $message"
;;
"WARN")
echo "[$timestamp] [WARN] $message" >&2
;;
"ERROR")
echo "[$timestamp] [ERROR] $message" >&2
;;
"DEBUG")
if [ "${DEBUG:-0}" = "1" ]; then
echo "[$timestamp] [DEBUG] $message" >&2
fi
;;
esac
}

# 配置管理函数
load_config() {
local config_file=${1:-config.conf}

if [ -f "$config_file" ]; then
log "INFO" "加载配置文件: $config_file"
source "$config_file"
else
log "WARN" "配置文件不存在: $config_file,使用默认配置"
# 设置默认配置
DB_HOST="localhost"
DB_PORT="3306"
LOG_LEVEL="INFO"
fi
}

# 函数测试
test_functions() {
echo "=== 函数测试 ==="

# 测试基本函数
greet "世界"

# 测试数学函数
result=$(add_numbers 10 20)
echo "10 + 20 = $result"

# 测试递归函数
fact=$(factorial 5)
echo "5! = $fact"

# 测试数组处理
numbers=(5 2 8 1 9)
echo "原数组: ${numbers[@]}"

sum=$(process_array numbers "sum")
echo "数组和: $sum"

max=$(process_array numbers "max")
echo "最大值: $max"

process_array numbers "sort"
echo "排序后: ${numbers[@]}"

# 测试日志函数
log "INFO" "这是一条信息"
log "WARN" "这是一条警告"
log "ERROR" "这是一条错误"

DEBUG=1 log "DEBUG" "这是调试信息"
}

# 设置错误处理
trap 'handle_error $? $LINENO "$BASH_COMMAND"' ERR
trap cleanup EXIT

# 执行测试
test_functions

模块化脚本设计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/bin/bash
# 模块化脚本示例 - 主脚本 main.sh

# 脚本配置
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
LIB_DIR="$SCRIPT_DIR/lib"
CONFIG_DIR="$SCRIPT_DIR/config"

# 加载库文件
source "$LIB_DIR/utils.sh"
source "$LIB_DIR/database.sh"
source "$LIB_DIR/network.sh"

# 加载配置
load_config "$CONFIG_DIR/app.conf"

# 主函数
main() {
local action=${1:-help}

case "$action" in
"backup")
backup_database
;;
"monitor")
monitor_system
;;
"deploy")
deploy_application "$2"
;;
"test")
run_tests
;;
"help"|*)
show_help
;;
esac
}

# 帮助信息
show_help() {
cat << EOF
用法: $0 <action> [options]

可用操作:
backup 备份数据库
monitor 监控系统状态
deploy <env> 部署应用到指定环境
test 运行测试
help 显示此帮助信息

示例:
$0 backup
$0 deploy production
$0 monitor
EOF
}

# 执行主函数
main "$@"

创建库文件 lib/utils.sh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#!/bin/bash
# 工具函数库 - lib/utils.sh

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 彩色输出函数
print_success() {
echo -e "${GREEN}✓ $1${NC}"
}

print_error() {
echo -e "${RED}✗ $1${NC}" >&2
}

print_warning() {
echo -e "${YELLOW}⚠ $1${NC}" >&2
}

print_info() {
echo -e "${BLUE}ℹ $1${NC}"
}

# 进度条函数
show_progress() {
local current=$1
local total=$2
local width=50
local percentage=$((current * 100 / total))
local completed=$((current * width / total))

printf "\r["
printf "%*s" $completed | tr ' ' '='
printf "%*s" $((width - completed)) | tr ' ' '-'
printf "] %d%% (%d/%d)" $percentage $current $total

if [ $current -eq $total ]; then
echo
fi
}

# 确认函数
confirm() {
local message=${1:-"确认继续吗?"}
local default=${2:-"n"}

while true; do
if [ "$default" = "y" ]; then
read -p "$message [Y/n]: " choice
choice=${choice:-y}
else
read -p "$message [y/N]: " choice
choice=${choice:-n}
fi

case "$choice" in
[Yy]|[Yy][Ee][Ss])
return 0
;;
[Nn]|[Nn][Oo])
return 1
;;
*)
echo "请输入 y 或 n"
;;
esac
done
}

# 重试函数
retry() {
local max_attempts=$1
local delay=$2
shift 2
local command="$@"

local attempt=1
while [ $attempt -le $max_attempts ]; do
print_info "尝试执行 (第 $attempt 次): $command"

if eval "$command"; then
print_success "命令执行成功"
return 0
else
print_warning "命令执行失败 (第 $attempt 次)"

if [ $attempt -lt $max_attempts ]; then
print_info "等待 $delay 秒后重试..."
sleep $delay
fi
fi

((attempt++))
done

print_error "命令执行失败,已达到最大重试次数"
return 1
}

# 文件操作函数
safe_copy() {
local source=$1
local destination=$2
local backup_suffix=".bak.$(date +%Y%m%d_%H%M%S)"

if [ ! -f "$source" ]; then
print_error "源文件不存在: $source"
return 1
fi

# 如果目标文件存在,先备份
if [ -f "$destination" ]; then
print_info "备份现有文件: $destination$backup_suffix"
cp "$destination" "$destination$backup_suffix"
fi

# 复制文件
if cp "$source" "$destination"; then
print_success "文件复制成功: $source -> $destination"
return 0
else
print_error "文件复制失败"
return 1
fi
}

# 检查依赖
check_dependencies() {
local dependencies=("$@")
local missing=()

for cmd in "${dependencies[@]}"; do
if ! command -v "$cmd" > /dev/null 2>&1; then
missing+=("$cmd")
fi
done

if [ ${#missing[@]} -gt 0 ]; then
print_error "缺少以下依赖: ${missing[*]}"
return 1
else
print_success "所有依赖检查通过"
return 0
fi
}

# 临时文件管理
create_temp_file() {
local prefix=${1:-"script"}
local temp_file=$(mktemp "/tmp/${prefix}.XXXXXX")
echo "$temp_file"
}

cleanup_temp_files() {
local pattern=${1:-"script.*"}
find /tmp -name "$pattern" -user "$(whoami)" -delete 2>/dev/null
print_info "临时文件清理完成"
}

文件和文本处理

高级文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/bin/bash
# 高级文件处理脚本

# 批量文件重命名
batch_rename() {
local directory=${1:-.}
local pattern=$2
local replacement=$3

if [ $# -lt 3 ]; then
echo "用法: batch_rename <目录> <模式> <替换>"
return 1
fi

local count=0
for file in "$directory"/*; do
if [ -f "$file" ]; then
local basename=$(basename "$file")
local new_name=$(echo "$basename" | sed "s/$pattern/$replacement/g")

if [ "$basename" != "$new_name" ]; then
local new_path="$directory/$new_name"
if mv "$file" "$new_path"; then
echo "重命名: $basename -> $new_name"
((count++))
else
echo "重命名失败: $basename" >&2
fi
fi
fi
done

echo "共重命名 $count 个文件"
}

# 文件内容替换
replace_in_files() {
local directory=$1
local file_pattern=$2
local search_pattern=$3
local replacement=$4
local backup=${5:-true}

if [ $# -lt 4 ]; then
echo "用法: replace_in_files <目录> <文件模式> <搜索模式> <替换内容> [备份:true/false]"
return 1
fi

local backup_suffix=""
if [ "$backup" = "true" ]; then
backup_suffix=".bak.$(date +%Y%m%d_%H%M%S)"
fi

find "$directory" -name "$file_pattern" -type f | while read -r file; do
if grep -q "$search_pattern" "$file"; then
echo "处理文件: $file"

# 备份原文件
if [ "$backup" = "true" ]; then
cp "$file" "$file$backup_suffix"
fi

# 执行替换
sed -i "s/$search_pattern/$replacement/g" "$file"
echo " 替换完成"
fi
done
}

# 文件去重
deduplicate_files() {
local directory=${1:-.}
local dry_run=${2:-false}

echo "在目录 $directory 中查找重复文件..."

# 使用MD5计算文件哈希
declare -A file_hashes
declare -A hash_files

find "$directory" -type f | while read -r file; do
local hash=$(md5sum "$file" | cut -d' ' -f1)
local size=$(stat -c%s "$file")
local key="${hash}_${size}"

if [ -n "${hash_files[$key]}" ]; then
echo "发现重复文件:"
echo " 原文件: ${hash_files[$key]}"
echo " 重复文件: $file"

if [ "$dry_run" = "false" ]; then
if confirm "删除重复文件 $file"; then
rm "$file"
echo " 已删除: $file"
fi
fi
else
hash_files[$key]="$file"
fi
done
}

# 文件同步
sync_directories() {
local source_dir=$1
local target_dir=$2
local options=${3:-"--archive --verbose"}

if [ ! -d "$source_dir" ]; then
echo "源目录不存在: $source_dir" >&2
return 1
fi

# 创建目标目录
mkdir -p "$target_dir"

echo "同步目录: $source_dir -> $target_dir"

# 使用rsync同步
if command -v rsync > /dev/null; then
rsync $options "$source_dir/" "$target_dir/"
else
# 备用方案:使用cp
cp -r "$source_dir"/* "$target_dir/"
fi

echo "同步完成"
}

# 文件压缩和归档
archive_old_files() {
local source_dir=$1
local archive_dir=$2
local days_old=${3:-30}
local compress=${4:-true}

if [ ! -d "$source_dir" ]; then
echo "源目录不存在: $source_dir" >&2
return 1
fi

mkdir -p "$archive_dir"

local archive_name="archive_$(date +%Y%m%d_%H%M%S)"
local temp_dir="/tmp/$archive_name"
mkdir -p "$temp_dir"

echo "查找 $days_old 天前的文件..."

# 查找旧文件
local file_count=0
find "$source_dir" -type f -mtime +$days_old | while read -r file; do
local relative_path=${file#$source_dir/}
local target_path="$temp_dir/$relative_path"

# 创建目标目录结构
mkdir -p "$(dirname "$target_path")"

# 移动文件
mv "$file" "$target_path"
((file_count++))
done

if [ $file_count -gt 0 ]; then
echo "归档 $file_count 个文件"

# 创建归档
if [ "$compress" = "true" ]; then
tar -czf "$archive_dir/$archive_name.tar.gz" -C "/tmp" "$archive_name"
else
tar -cf "$archive_dir/$archive_name.tar" -C "/tmp" "$archive_name"
fi

# 清理临时目录
rm -rf "$temp_dir"

echo "归档完成: $archive_dir/$archive_name.tar.gz"
else
echo "没有找到需要归档的文件"
rm -rf "$temp_dir"
fi
}

文本处理和分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#!/bin/bash
# 文本处理和分析脚本

# 日志分析函数
analyze_log_file() {
local log_file=$1
local output_dir=${2:-./log_analysis}

if [ ! -f "$log_file" ]; then
echo "日志文件不存在: $log_file" >&2
return 1
fi

mkdir -p "$output_dir"
local base_name=$(basename "$log_file" .log)

echo "分析日志文件: $log_file"

# 基本统计
echo "=== 基本统计 ===" > "$output_dir/${base_name}_analysis.txt"
echo "总行数: $(wc -l < "$log_file")" >> "$output_dir/${base_name}_analysis.txt"
echo "文件大小: $(du -h "$log_file" | cut -f1)" >> "$output_dir/${base_name}_analysis.txt"
echo "最早记录: $(head -1 "$log_file" | cut -d' ' -f1-2)" >> "$output_dir/${base_name}_analysis.txt"
echo "最新记录: $(tail -1 "$log_file" | cut -d' ' -f1-2)" >> "$output_dir/${base_name}_analysis.txt"
echo "" >> "$output_dir/${base_name}_analysis.txt"

# 错误统计
echo "=== 错误统计 ===" >> "$output_dir/${base_name}_analysis.txt"
grep -i "error\|fail\|exception" "$log_file" | wc -l | \
xargs echo "错误数量:" >> "$output_dir/${base_name}_analysis.txt"

# IP地址统计(适用于访问日志)
if grep -q "^\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}" "$log_file"; then
echo "=== IP访问统计 (前10) ===" >> "$output_dir/${base_name}_analysis.txt"
awk '{print $1}' "$log_file" | sort | uniq -c | sort -nr | head -10 >> "$output_dir/${base_name}_analysis.txt"
fi

# 状态码统计(适用于Web访问日志)
if grep -q " [0-9]\{3\} " "$log_file"; then
echo "=== HTTP状态码统计 ===" >> "$output_dir/${base_name}_analysis.txt"
awk '{print $9}' "$log_file" | sort | uniq -c | sort -nr >> "$output_dir/${base_name}_analysis.txt"
fi

# 时间分布统计
echo "=== 小时访问分布 ===" >> "$output_dir/${base_name}_analysis.txt"
awk '{print $4}' "$log_file" | cut -d: -f2 | sort | uniq -c | sort -k2n >> "$output_dir/${base_name}_analysis.txt"

echo "分析完成,结果保存在: $output_dir/${base_name}_analysis.txt"
}

# CSV文件处理
process_csv_file() {
local csv_file=$1
local operation=$2
local column=${3:-1}

if [ ! -f "$csv_file" ]; then
echo "CSV文件不存在: $csv_file" >&2
return 1
fi

case "$operation" in
"count")
echo "总行数: $(wc -l < "$csv_file")"
;;
"sum")
awk -F',' -v col="$column" '{sum += $col} END {print "第"col"列总和:", sum}' "$csv_file"
;;
"average")
awk -F',' -v col="$column" '{sum += $col; count++} END {print "第"col"列平均值:", sum/count}' "$csv_file"
;;
"unique")
awk -F',' -v col="$column" '{print $col}' "$csv_file" | sort | uniq -c | sort -nr
;;
"filter")
local filter_value=$4
if [ -z "$filter_value" ]; then
echo "请提供过滤值" >&2
return 1
fi
awk -F',' -v col="$column" -v val="$filter_value" '$col == val' "$csv_file"
;;
*)
echo "支持的操作: count, sum, average, unique, filter"
;;
esac
}

# 文本格式转换
convert_text_format() {
local input_file=$1
local output_format=$2
local output_file=$3

if [ ! -f "$input_file" ]; then
echo "输入文件不存在: $input_file" >&2
return 1
fi

case "$output_format" in
"uppercase")
tr '[:lower:]' '[:upper:]' < "$input_file" > "$output_file"
;;
"lowercase")
tr '[:upper:]' '[:lower:]' < "$input_file" > "$output_file"
;;
"remove_spaces")
tr -d ' ' < "$input_file" > "$output_file"
;;
"unix_line_endings")
dos2unix "$input_file" -o "$output_file" 2>/dev/null || \
sed 's/\r$//' "$input_file" > "$output_file"
;;
"windows_line_endings")
unix2dos "$input_file" -o "$output_file" 2>/dev/null || \
sed 's/$/\r/' "$input_file" > "$output_file"
;;
"remove_empty_lines")
grep -v '^$' "$input_file" > "$output_file"
;;
"add_line_numbers")
nl -ba "$input_file" > "$output_file"
;;
*)
echo "支持的格式: uppercase, lowercase, remove_spaces, unix_line_endings, windows_line_endings, remove_empty_lines, add_line_numbers"
;;
esac

echo "转换完成: $input_file -> $output_file ($output_format)"
}

# 文本搜索和替换
advanced_text_search() {
local directory=$1
local search_pattern=$2
local file_pattern=${3:-"*"}
local context_lines=${4:-0}

if [ $# -lt 2 ]; then
echo "用法: advanced_text_search <目录> <搜索模式> [文件模式] [上下文行数]"
return 1
fi

echo "在目录 $directory 中搜索模式: $search_pattern"
echo "文件模式: $file_pattern"
echo "上下文行数: $context_lines"
echo "================================"

local total_matches=0
local total_files=0

find "$directory" -name "$file_pattern" -type f | while read -r file; do
local matches=$(grep -c "$search_pattern" "$file" 2>/dev/null || echo 0)

if [ "$matches" -gt 0 ]; then
echo "文件: $file (匹配 $matches 次)"

if [ "$context_lines" -gt 0 ]; then
grep -n -C "$context_lines" "$search_pattern" "$file"
else
grep -n "$search_pattern" "$file"
fi

echo ""
total_matches=$((total_matches + matches))
total_files=$((total_files + 1))
fi
done

echo "搜索完成: 在 $total_files 个文件中找到 $total_matches 个匹配"
}

# 生成文本报告
generate_text_report() {
local title=$1
local data_file=$2
local output_file=$3

cat > "$output_file" << EOF
================================================================================
$title
================================================================================
生成时间: $(date)
数据来源: $data_file
================================================================================

EOF

if [ -f "$data_file" ]; then
echo "数据内容:" >> "$output_file"
echo "----------------------------------------" >> "$output_file"
cat "$data_file" >> "$output_file"
echo "" >> "$output_file"
echo "----------------------------------------" >> "$output_file"
echo "总行数: $(wc -l < "$data_file")" >> "$output_file"
echo "文件大小: $(du -h "$data_file" | cut -f1)" >> "$output_file"
else
echo "数据文件不存在: $data_file" >> "$output_file"
fi

echo "" >> "$output_file"
echo "报告生成完成。" >> "$output_file"
echo "=================================================================================" >> "$output_file"

echo "报告已生成: $output_file"
}

# 测试文本处理功能
test_text_processing() {
echo "=== 文本处理功能测试 ==="

# 创建测试CSV文件
cat > /tmp/test.csv << EOF
姓名,年龄,城市
张三,25,北京
李四,30,上海
王五,28,广州
赵六,35,深圳
EOF

echo "CSV文件处理测试:"
process_csv_file "/tmp/test.csv" "count"
process_csv_file "/tmp/test.csv" "unique" 3

# 创建测试文本文件
cat > /tmp/test.txt << EOF
Hello World
HELLO WORLD
hello world
EOF

echo -e "\n文本格式转换测试:"
convert_text_format "/tmp/test.txt" "uppercase" "/tmp/test_upper.txt"
echo "转换结果:"
cat /tmp/test_upper.txt

# 清理测试文件
rm -f /tmp/test.csv /tmp/test.txt /tmp/test_upper.txt
}

# 执行测试
test_text_processing

系统监控和自动化

系统监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#!/bin/bash
# 综合系统监控脚本

# 配置文件
CONFIG_FILE="/etc/system-monitor.conf"
LOG_FILE="/var/log/system-monitor.log"
ALERT_LOG="/var/log/system-alerts.log"
PID_FILE="/var/run/system-monitor.pid"

# 默认配置
CPU_THRESHOLD=80
MEMORY_THRESHOLD=80
DISK_THRESHOLD=80
LOAD_THRESHOLD=5.0
CHECK_INTERVAL=60
ALERT_EMAIL=""
SLACK_WEBHOOK=""

# 加载配置
load_monitor_config() {
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
log_message "INFO" "配置文件已加载: $CONFIG_FILE"
else
log_message "WARN" "配置文件不存在,使用默认配置"
fi
}

# 日志记录
log_message() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"

if [ "$level" = "ALERT" ]; then
echo "[$timestamp] $message" >> "$ALERT_LOG"
fi
}

# 发送告警
send_alert() {
local alert_type=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')

log_message "ALERT" "[$alert_type] $message"

# 邮件告警
if [ ! -z "$ALERT_EMAIL" ]; then
echo "$message" | mail -s "System Alert: $alert_type - $(hostname)" "$ALERT_EMAIL"
fi

# Slack告警
if [ ! -z "$SLACK_WEBHOOK" ]; then
local payload=$(cat << EOF
{
"text": "🚨 System Alert",
"attachments": [
{
"color": "danger",
"fields": [
{
"title": "Alert Type",
"value": "$alert_type",
"short": true
},
{
"title": "Host",
"value": "$(hostname)",
"short": true
},
{
"title": "Time",
"value": "$timestamp",
"short": true
},
{
"title": "Message",
"value": "$message",
"short": false
}
]
}
]
}
EOF
)

curl -X POST -H 'Content-type: application/json' \
--data "$payload" "$SLACK_WEBHOOK" > /dev/null 2>&1
fi
}

# CPU监控
monitor_cpu() {
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
local cpu_int=${cpu_usage%.*}

log_message "INFO" "CPU使用率: ${cpu_usage}%"

if [ "$cpu_int" -gt "$CPU_THRESHOLD" ]; then
local top_processes=$(ps aux --sort=-%cpu | head -6 | tail -5 | awk '{print $11}' | tr '\n' ', ')
send_alert "HIGH_CPU" "CPU使用率过高: ${cpu_usage}% (阈值: ${CPU_THRESHOLD}%). 高CPU进程: $top_processes"
fi

# 系统负载检查
local load_avg=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}' | tr -d ',')
log_message "INFO" "系统负载: $load_avg"

if (( $(echo "$load_avg > $LOAD_THRESHOLD" | bc -l) )); then
send_alert "HIGH_LOAD" "系统负载过高: $load_avg (阈值: $LOAD_THRESHOLD)"
fi
}

# 内存监控
monitor_memory() {
local mem_info=$(free | grep Mem)
local total_mem=$(echo $mem_info | awk '{print $2}')
local used_mem=$(echo $mem_info | awk '{print $3}')
local mem_usage=$(echo "scale=1; $used_mem * 100 / $total_mem" | bc)
local mem_usage_int=${mem_usage%.*}

log_message "INFO" "内存使用率: ${mem_usage}%"

if [ "$mem_usage_int" -gt "$MEMORY_THRESHOLD" ]; then
local top_processes=$(ps aux --sort=-%mem | head -6 | tail -5 | awk '{print $11}' | tr '\n' ', ')
send_alert "HIGH_MEMORY" "内存使用率过高: ${mem_usage}% (阈值: ${MEMORY_THRESHOLD}%). 高内存进程: $top_processes"
fi

# Swap使用检查
local swap_info=$(free | grep Swap)
if [ ! -z "$swap_info" ]; then
local swap_used=$(echo $swap_info | awk '{print $3}')
if [ "$swap_used" -gt 0 ]; then
local swap_total=$(echo $swap_info | awk '{print $2}')
local swap_usage=$(echo "scale=1; $swap_used * 100 / $swap_total" | bc)
log_message "WARN" "Swap正在使用: ${swap_usage}%"

if [ "${swap_usage%.*}" -gt 50 ]; then
send_alert "HIGH_SWAP" "Swap使用率过高: ${swap_usage}%"
fi
fi
fi
}

# 磁盘监控
monitor_disk() {
df -h | grep -E '^/dev/' | while read line; do
local usage=$(echo $line | awk '{print $5}' | cut -d'%' -f1)
local mount_point=$(echo $line | awk '{print $6}')
local filesystem=$(echo $line | awk '{print $1}')

log_message "INFO" "磁盘 $mount_point 使用率: ${usage}%"

if [ "$usage" -gt "$DISK_THRESHOLD" ]; then
send_alert "HIGH_DISK" "磁盘 $mount_point ($filesystem) 使用率过高: ${usage}% (阈值: ${DISK_THRESHOLD}%)"
fi
done

# 检查inode使用率
df -i | grep -E '^/dev/' | while read line; do
local inode_usage=$(echo $line | awk '{print $5}' | cut -d'%' -f1)
local mount_point=$(echo $line | awk '{print $6}')

if [ "$inode_usage" -gt 80 ]; then
send_alert "HIGH_INODE" "磁盘 $mount_point inode使用率过高: ${inode_usage}%"
fi
done
}

# 网络监控
monitor_network() {
# 检查网络连接数
local connections=$(netstat -tupln | grep ESTABLISHED | wc -l)
log_message "INFO" "当前网络连接数: $connections"

if [ "$connections" -gt 1000 ]; then
send_alert "HIGH_CONNECTIONS" "网络连接数过多: $connections"
fi

# 检查网络接口状态
for interface in $(ls /sys/class/net/ | grep -v lo); do
if [ -f "/sys/class/net/$interface/operstate" ]; then
local state=$(cat /sys/class/net/$interface/operstate)
if [ "$state" != "up" ]; then
send_alert "NETWORK_DOWN" "网络接口 $interface 状态异常: $state"
fi
fi
done

# 检查网络错误
for interface in $(ls /sys/class/net/ | grep -v lo); do
if [ -f "/sys/class/net/$interface/statistics/rx_errors" ]; then
local rx_errors=$(cat /sys/class/net/$interface/statistics/rx_errors)
local tx_errors=$(cat /sys/class/net/$interface/statistics/tx_errors)

if [ "$rx_errors" -gt 100 ] || [ "$tx_errors" -gt 100 ]; then
send_alert "NETWORK_ERRORS" "网络接口 $interface 错误过多: RX=$rx_errors, TX=$tx_errors"
fi
fi
done
}

# 服务监控
monitor_services() {
local critical_services=("ssh" "nginx" "mysql" "redis" "docker")

for service in "${critical_services[@]}"; do
if systemctl list-unit-files | grep -q "^$service.service"; then
if ! systemctl is-active --quiet "$service"; then
send_alert "SERVICE_DOWN" "关键服务 $service 未运行"
else
log_message "INFO" "服务 $service 运行正常"
fi
fi
done

# 检查失败的服务
local failed_services=$(systemctl list-units --failed --no-legend | wc -l)
if [ "$failed_services" -gt 0 ]; then
local failed_list=$(systemctl list-units --failed --no-legend | awk '{print $1}' | tr '\n' ', ')
send_alert "SERVICES_FAILED" "发现 $failed_services 个失败的服务: $failed_list"
fi
}

# 进程监控
monitor_processes() {
# 检查僵尸进程
local zombie_count=$(ps aux | awk '$8 ~ /^Z/ { count++ } END { print count+0 }')
if [ "$zombie_count" -gt 0 ]; then
send_alert "ZOMBIE_PROCESSES" "发现 $zombie_count 个僵尸进程"
fi

# 检查高CPU进程
local high_cpu_processes=$(ps aux --sort=-%cpu | awk 'NR>1 && $3>50 {print $11}' | head -5 | tr '\n' ', ')
if [ ! -z "$high_cpu_processes" ]; then
log_message "WARN" "高CPU使用进程: $high_cpu_processes"
fi

# 检查高内存进程
local high_mem_processes=$(ps aux --sort=-%mem | awk 'NR>1 && $4>20 {print $11}' | head -5 | tr '\n' ', ')
if [ ! -z "$high_mem_processes" ]; then
log_message "WARN" "高内存使用进程: $high_mem_processes"
fi
}

# 日志监控
monitor_logs() {
# 检查系统错误日志
local error_count=$(journalctl --since "5 minutes ago" --priority=err | wc -l)
if [ "$error_count" -gt 10 ]; then
send_alert "HIGH_ERROR_RATE" "最近5分钟内系统错误过多: $error_count 条"
fi

# 检查登录失败
local failed_logins=$(journalctl --since "5 minutes ago" | grep -i "failed\|failure" | wc -l)
if [ "$failed_logins" -gt 5 ]; then
send_alert "FAILED_LOGINS" "最近5分钟内登录失败过多: $failed_logins 次"
fi
}

# 生成监控报告
generate_monitor_report() {
local report_file="/tmp/system-monitor-report-$(date +%Y%m%d_%H%M%S).txt"

cat > "$report_file" << EOF
================================================================================
系统监控报告
================================================================================
生成时间: $(date)
主机名: $(hostname)
系统: $(uname -a)
运行时间: $(uptime)
================================================================================

CPU信息:
$(top -bn1 | grep "Cpu(s)")
$(uptime | awk -F'load average:' '{print "负载平均值:" $2}')

内存信息:
$(free -h)

磁盘使用情况:
$(df -h)

网络连接:
活动连接数: $(netstat -tupln | grep ESTABLISHED | wc -l)

系统服务状态:
$(systemctl list-units --failed --no-legend | wc -l) 个服务失败

最近告警 (最近24小时):
$(tail -20 "$ALERT_LOG" 2>/dev/null || echo "无告警记录")

================================================================================
报告结束
================================================================================
EOF

echo "$report_file"
}

# 主监控循环
monitor_loop() {
log_message "INFO" "系统监控启动"

while true; do
log_message "INFO" "开始监控检查"

monitor_cpu
monitor_memory
monitor_disk
monitor_network
monitor_services
monitor_processes
monitor_logs

log_message "INFO" "监控检查完成,等待 $CHECK_INTERVAL 秒"
sleep "$CHECK_INTERVAL"
done
}

# 守护进程管理
start_daemon() {
if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
echo "监控进程已在运行 (PID: $(cat "$PID_FILE"))"
return 1
fi

echo "启动系统监控守护进程..."
nohup "$0" --loop > /dev/null 2>&1 &
echo $! > "$PID_FILE"
echo "监控进程已启动 (PID: $!)"
}

stop_daemon() {
if [ -f "$PID_FILE" ]; then
local pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
kill "$pid"
rm -f "$PID_FILE"
echo "监控进程已停止"
else
echo "监控进程未运行"
rm -f "$PID_FILE"
fi
else
echo "PID文件不存在"
fi
}

status_daemon() {
if [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
echo "监控进程正在运行 (PID: $(cat "$PID_FILE"))"
else
echo "监控进程未运行"
fi
}

# 主函数
main() {
case "${1:-help}" in
"start")
load_monitor_config
start_daemon
;;
"stop")
stop_daemon
;;
"restart")
stop_daemon
sleep 2
load_monitor_config
start_daemon
;;
"status")
status_daemon
;;
"check")
load_monitor_config
log_message "INFO" "执行单次检查"
monitor_cpu
monitor_memory
monitor_disk
monitor_network
monitor_services
monitor_processes
monitor_logs
;;
"report")
report_file=$(generate_monitor_report)
echo "监控报告已生成: $report_file"
;;
"--loop")
load_monitor_config
monitor_loop
;;
"help"|*)
cat << EOF
系统监控脚本

用法: $0 <command>

命令:
start 启动监控守护进程
stop 停止监控守护进程
restart 重启监控守护进程
status 查看监控进程状态
check 执行单次检查
report 生成监控报告
help 显示此帮助信息

配置文件: $CONFIG_FILE
日志文件: $LOG_FILE
告警日志: $ALERT_LOG
EOF
;;
esac
}

# 执行主函数
main "$@"

自动化部署脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
#!/bin/bash
# 自动化部署脚本

# 配置
APP_NAME="myapp"
DEPLOY_USER="deploy"
DEPLOY_GROUP="deploy"
APP_DIR="/opt/$APP_NAME"
BACKUP_DIR="/backup/$APP_NAME"
LOG_FILE="/var/log/deploy.log"
CONFIG_FILE="deploy.conf"

# 环境配置
declare -A ENVIRONMENTS=(
["dev"]="dev.example.com"
["staging"]="staging.example.com"
["production"]="prod.example.com"
)

# 部署配置
declare -A DEPLOY_CONFIG=(
["git_repo"]="https://github.com/user/myapp.git"
["branch"]="main"
["build_command"]="npm run build"
["start_command"]="npm start"
["health_check_url"]="http://localhost:3000/health"
["health_check_timeout"]="30"
)

# 日志记录
deploy_log() {
local level=$1
local message=$2
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
}

# 错误处理
handle_deploy_error() {
local exit_code=$1
local step=$2

deploy_log "ERROR" "部署失败在步骤: $step (退出码: $exit_code)"

# 回滚
if [ "$AUTO_ROLLBACK" = "true" ]; then
deploy_log "INFO" "开始自动回滚"
rollback_deployment
fi

# 发送告警
send_deploy_alert "DEPLOY_FAILED" "部署失败: $step"

exit $exit_code
}

# 发送部署告警
send_deploy_alert() {
local alert_type=$1
local message=$2

deploy_log "ALERT" "[$alert_type] $message"

# 这里可以集成邮件、Slack等告警
if [ ! -z "$SLACK_WEBHOOK" ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\":\"🚀 Deploy Alert: $message\"}" \
"$SLACK_WEBHOOK" > /dev/null 2>&1
fi
}

# 环境检查
check_environment() {
local env=$1

deploy_log "INFO" "检查部署环境: $env"

# 检查必要的命令
local required_commands=("git" "node" "npm")
for cmd in "${required_commands[@]}"; do
if ! command -v "$cmd" > /dev/null; then
deploy_log "ERROR" "缺少必要命令: $cmd"
return 1
fi
done

# 检查目录权限
if [ ! -w "$(dirname "$APP_DIR")" ]; then
deploy_log "ERROR" "没有写入权限: $(dirname "$APP_DIR")"
return 1
fi

# 检查磁盘空间
local available_space=$(df "$(dirname "$APP_DIR")" | tail -1 | awk '{print $4}')
if [ "$available_space" -lt 1048576 ]; then # 1GB
deploy_log "ERROR" "磁盘空间不足: ${available_space}KB"
return 1
fi

deploy_log "INFO" "环境检查通过"
return 0
}

# 创建备份
create_backup() {
local backup_name="backup_$(date +%Y%m%d_%H%M%S)"
local backup_path="$BACKUP_DIR/$backup_name"

deploy_log "INFO" "创建备份: $backup_path"

if [ -d "$APP_DIR" ]; then
mkdir -p "$BACKUP_DIR"
cp -r "$APP_DIR" "$backup_path"

# 保留最近10个备份
ls -t "$BACKUP_DIR" | tail -n +11 | xargs -I {} rm -rf "$BACKUP_DIR/{}"

deploy_log "INFO" "备份创建成功: $backup_path"
echo "$backup_path"
else
deploy_log "INFO" "应用目录不存在,跳过备份"
fi
}

# 下载代码
download_code() {
local branch=${1:-${DEPLOY_CONFIG["branch"]}}
local temp_dir="/tmp/deploy_$$"

deploy_log "INFO" "下载代码分支: $branch"

# 克隆代码
if ! git clone -b "$branch" "${DEPLOY_CONFIG["git_repo"]}" "$temp_dir"; then
deploy_log "ERROR" "代码下载失败"
return 1
fi

# 移动到应用目录
mkdir -p "$APP_DIR"
rsync -av --delete "$temp_dir/" "$APP_DIR/"

# 清理临时目录
rm -rf "$temp_dir"

deploy_log "INFO" "代码下载完成"
return 0
}

# 构建应用
build_application() {
deploy_log "INFO" "开始构建应用"

cd "$APP_DIR" || return 1

# 安装依赖
if [ -f "package.json" ]; then
deploy_log "INFO" "安装Node.js依赖"
npm ci --production
fi

# 执行构建命令
if [ ! -z "${DEPLOY_CONFIG["build_command"]}" ]; then
deploy_log "INFO" "执行构建命令: ${DEPLOY_CONFIG["build_command"]}"
eval "${DEPLOY_CONFIG["build_command"]}"
fi

deploy_log "INFO" "应用构建完成"
return 0
}

# 配置应用
configure_application() {
local env=$1

deploy_log "INFO" "配置应用环境: $env"

# 复制环境配置文件
if [ -f "$APP_DIR/config/$env.conf" ]; then
cp "$APP_DIR/config/$env.conf" "$APP_DIR/.env"
deploy_log "INFO" "环境配置文件已复制"
fi

# 设置文件权限
chown -R "$DEPLOY_USER:$DEPLOY_GROUP" "$APP_DIR"
chmod -R 755 "$APP_DIR"

# 创建必要的目录
mkdir -p "$APP_DIR/logs"
mkdir -p "$APP_DIR/tmp"

deploy_log "INFO" "应用配置完成"
return 0
}

# 启动应用
start_application() {
deploy_log "INFO" "启动应用"

cd "$APP_DIR" || return 1

# 停止现有进程
if [ -f "$APP_DIR/app.pid" ]; then
local old_pid=$(cat "$APP_DIR/app.pid")
if kill -0 "$old_pid" 2>/dev/null; then
deploy_log "INFO" "停止现有进程: $old_pid"
kill "$old_pid"
sleep 5
fi
fi

# 启动新进程
nohup ${DEPLOY_CONFIG["start_command"]} > "$APP_DIR/logs/app.log" 2>&1 &
echo $! > "$APP_DIR/app.pid"

deploy_log "INFO" "应用已启动 (PID: $!)"
return 0
}

# 健康检查
health_check() {
local url=${DEPLOY_CONFIG["health_check_url"]}
local timeout=${DEPLOY_CONFIG["health_check_timeout"]}
local max_attempts=10
local attempt=1

deploy_log "INFO" "开始健康检查: $url"

while [ $attempt -le $max_attempts ]; do
deploy_log "INFO" "健康检查尝试 $attempt/$max_attempts"

if curl -f -s --max-time "$timeout" "$url" > /dev/null; then
deploy_log "INFO" "健康检查通过"
return 0
fi

sleep 5
((attempt++))
done

deploy_log "ERROR" "健康检查失败"
return 1
}

# 回滚部署
rollback_deployment() {
deploy_log "INFO" "开始回滚部署"

# 查找最新的备份
local latest_backup=$(ls -t "$BACKUP_DIR" | head -1)

if [ -z "$latest_backup" ]; then
deploy_log "ERROR" "没有找到备份文件"
return 1
fi

local backup_path="$BACKUP_DIR/$latest_backup"
deploy_log "INFO" "使用备份: $backup_path"

# 停止当前应用
if [ -f "$APP_DIR/app.pid" ]; then
local pid=$(cat "$APP_DIR/app.pid")
if kill -0 "$pid" 2>/dev/null; then
kill "$pid"
fi
fi

# 恢复备份
rm -rf "$APP_DIR"
cp -r "$backup_path" "$APP_DIR"

# 重启应用
start_application

if health_check; then
deploy_log "INFO" "回滚成功"
send_deploy_alert "ROLLBACK_SUCCESS" "应用已成功回滚到: $latest_backup"
return 0
else
deploy_log "ERROR" "回滚后健康检查失败"
return 1
fi
}

# 部署到指定环境
deploy_to_environment() {
local env=$1
local branch=${2:-${DEPLOY_CONFIG["branch"]}}

if [ -z "${ENVIRONMENTS[$env]}" ]; then
deploy_log "ERROR" "未知环境: $env"
return 1
fi

deploy_log "INFO" "开始部署到环境: $env"
send_deploy_alert "DEPLOY_START" "开始部署到 $env 环境"

# 设置错误处理
set -e
trap 'handle_deploy_error $? "部署过程"' ERR

# 执行部署步骤
check_environment "$env" || handle_deploy_error $? "环境检查"

local backup_path=$(create_backup)

download_code "$branch" || handle_deploy_error $? "代码下载"

build_application || handle_deploy_error $? "应用构建"

configure_application "$env" || handle_deploy_error $? "应用配置"

start_application || handle_deploy_error $? "应用启动"

health_check || handle_deploy_error $? "健康检查"

# 清理错误处理
set +e
trap - ERR

deploy_log "INFO" "部署成功完成"
send_deploy_alert "DEPLOY_SUCCESS" "成功部署到 $env 环境"

return 0
}

# 蓝绿部署
blue_green_deploy() {
local env=$1
local branch=${2:-${DEPLOY_CONFIG["branch"]}}

deploy_log "INFO" "开始蓝绿部署到环境: $env"

# 确定当前活跃环境
local current_env="blue"
local target_env="green"

if [ -f "/tmp/current_env" ]; then
current_env=$(cat /tmp/current_env)
if [ "$current_env" = "blue" ]; then
target_env="green"
else
target_env="blue"
fi
fi

deploy_log "INFO" "当前环境: $current_env, 目标环境: $target_env"

# 部署到目标环境
local target_dir="${APP_DIR}_${target_env}"
local original_app_dir="$APP_DIR"
APP_DIR="$target_dir"

# 执行部署
deploy_to_environment "$env" "$branch"

# 切换流量
deploy_log "INFO" "切换流量到: $target_env"

# 更新负载均衡器配置(这里需要根据实际情况实现)
# update_load_balancer "$target_env"

# 更新当前环境标记
echo "$target_env" > /tmp/current_env

# 恢复原始APP_DIR
APP_DIR="$original_app_dir"

deploy_log "INFO" "蓝绿部署完成"
}

# 金丝雀部署
canary_deploy() {
local env=$1
local branch=${2:-${DEPLOY_CONFIG["branch"]}}
local traffic_percentage=${3:-10}

deploy_log "INFO" "开始金丝雀部署: $traffic_percentage% 流量"

# 部署金丝雀版本
local canary_dir="${APP_DIR}_canary"
local original_app_dir="$APP_DIR"
APP_DIR="$canary_dir"

deploy_to_environment "$env" "$branch"

# 配置流量分流(需要根据实际负载均衡器实现)
deploy_log "INFO" "配置 $traffic_percentage% 流量到金丝雀版本"

# 监控金丝雀版本
deploy_log "INFO" "监控金丝雀版本性能"
sleep 300 # 监控5分钟

# 检查错误率
local error_rate=$(check_error_rate "$canary_dir")

if [ "$error_rate" -lt 5 ]; then
deploy_log "INFO" "金丝雀版本表现良好,准备全量部署"
# 全量部署
APP_DIR="$original_app_dir"
deploy_to_environment "$env" "$branch"

# 清理金丝雀版本
rm -rf "$canary_dir"
else
deploy_log "ERROR" "金丝雀版本错误率过高: $error_rate%"
# 回滚金丝雀版本
rm -rf "$canary_dir"
return 1
fi

APP_DIR="$original_app_dir"
deploy_log "INFO" "金丝雀部署完成"
}

# 检查错误率
check_error_rate() {
local app_dir=$1
local log_file="$app_dir/logs/app.log"

if [ ! -f "$log_file" ]; then
echo "0"
return
fi

local total_requests=$(grep -c "REQUEST" "$log_file" || echo "1")
local error_requests=$(grep -c "ERROR" "$log_file" || echo "0")
local error_rate=$((error_requests * 100 / total_requests))

echo "$error_rate"
}

# 主函数
main() {
local action=${1:-help}
local env=$2
local branch=$3

# 加载配置
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
fi

case "$action" in
"deploy")
if [ -z "$env" ]; then
echo "请指定部署环境" >&2
exit 1
fi
deploy_to_environment "$env" "$branch"
;;
"rollback")
if [ -z "$env" ]; then
echo "请指定回滚环境" >&2
exit 1
fi
rollback_deployment
;;
"blue-green")
if [ -z "$env" ]; then
echo "请指定部署环境" >&2
exit 1
fi
blue_green_deploy "$env" "$branch"
;;
"canary")
if [ -z "$env" ]; then
echo "请指定部署环境" >&2
exit 1
fi
local percentage=${4:-10}
canary_deploy "$env" "$branch" "$percentage"
;;
"health")
health_check
;;
"backup")
create_backup
;;
"help"|*)
cat << EOF
自动化部署脚本

用法: $0 <action> <environment> [branch] [options]

操作:
deploy <env> [branch] 标准部署
rollback <env> 回滚部署
blue-green <env> [branch] 蓝绿部署
canary <env> [branch] [percent] 金丝雀部署
health 健康检查
backup 创建备份
help 显示帮助

环境:
dev, staging, production

示例:
$0 deploy production main
$0 rollback production
$0 blue-green staging feature-branch
$0 canary production main 20
EOF
;;
esac
}

# 执行主函数
main "$@"

最佳实践和调试技巧

脚本调试和优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
#!/bin/bash
# Shell脚本调试和优化最佳实践

# 调试选项设置
set -euo pipefail # 严格模式
# set -x # 调试模式,显示执行的命令

# 脚本信息
readonly SCRIPT_NAME=$(basename "$0")
readonly SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
readonly SCRIPT_VERSION="1.0.0"

# 调试函数
debug() {
if [ "${DEBUG:-0}" = "1" ]; then
echo "[DEBUG] $*" >&2
fi
}

# 性能测试函数
benchmark() {
local description=$1
shift
local command="$*"

echo "性能测试: $description"
time eval "$command"
echo "---"
}

# 内存使用监控
monitor_memory_usage() {
local pid=${1:-$$}

while kill -0 "$pid" 2>/dev/null; do
local mem_usage=$(ps -o pid,vsz,rss,comm -p "$pid" | tail -1)
echo "内存使用: $mem_usage"
sleep 1
done
}

# 错误处理最佳实践
error_handler() {
local line_no=$1
local error_code=$2
local command="$3"

echo "错误发生:" >&2
echo " 行号: $line_no" >&2
echo " 错误码: $error_code" >&2
echo " 命令: $command" >&2
echo " 调用栈:" >&2

# 打印调用栈
local frame=0
while caller $frame; do
((frame++))
done

exit "$error_code"
}

# 设置错误处理
trap 'error_handler ${LINENO} $? "$BASH_COMMAND"' ERR

# 参数验证函数
validate_parameters() {
local required_params=("$@")

for param in "${required_params[@]}"; do
if [ -z "${!param:-}" ]; then
echo "错误: 缺少必需参数 $param" >&2
return 1
fi
done
}

# 配置验证
validate_config() {
local config_file=$1

if [ ! -f "$config_file" ]; then
echo "配置文件不存在: $config_file" >&2
return 1
fi

# 检查配置文件语法
if ! bash -n "$config_file"; then
echo "配置文件语法错误: $config_file" >&2
return 1
fi

echo "配置文件验证通过: $config_file"
}

# 性能优化示例
optimize_file_processing() {
local file=$1
local output=$2

echo "=== 文件处理性能对比 ==="

# 方法1: 逐行读取 (较慢)
benchmark "逐行读取方法" '
while IFS= read -r line; do
echo "处理: $line"
done < "'$file'" > /dev/null
'

# 方法2: 批量处理 (较快)
benchmark "批量处理方法" '
sed "s/^/处理: /" "'$file'" > /dev/null
'

# 方法3: awk处理 (最快)
benchmark "awk处理方法" '
awk "{print \"处理: \" \$0}" "'$file'" > /dev/null
'
}

# 并发处理示例
parallel_processing_demo() {
local files=("$@")
local max_jobs=4

echo "=== 并发处理示例 ==="

# 串行处理
benchmark "串行处理" '
for file in "${files[@]}"; do
wc -l "$file" > /dev/null
done
'

# 并行处理
benchmark "并行处理" '
for file in "${files[@]}"; do
wc -l "$file" > /dev/null &

# 控制并发数
while [ $(jobs -r | wc -l) -ge '$max_jobs' ]; do
sleep 0.1
done
done
wait # 等待所有后台任务完成
'
}

# 内存优化技巧
memory_optimization_demo() {
echo "=== 内存优化技巧 ==="

# 大文件处理 - 避免一次性加载
large_file_processing() {
local file=$1

# 错误方式:一次性读取整个文件
# content=$(cat "$file") # 占用大量内存

# 正确方式:流式处理
while IFS= read -r line; do
# 处理每一行
echo "处理: $line" > /dev/null
done < "$file"
}

# 数组优化
array_optimization_demo() {
echo "数组使用优化:"

# 避免在循环中频繁修改大数组
local -a large_array=()

# 错误方式:频繁追加
# for i in {1..10000}; do
# large_array+=("item_$i")
# done

# 优化方式:预分配或批量操作
local temp_file=$(mktemp)
for i in {1..1000}; do
echo "item_$i" >> "$temp_file"
done

# 一次性读取
mapfile -t large_array < "$temp_file"
rm "$temp_file"

echo "数组大小: ${#large_array[@]}"
}

array_optimization_demo
}

# 代码质量检查
code_quality_check() {
local script_file=$1

echo "=== 代码质量检查 ==="

# 语法检查
if bash -n "$script_file"; then
echo "✓ 语法检查通过"
else
echo "✗ 语法检查失败"
return 1
fi

# ShellCheck检查(如果可用)
if command -v shellcheck > /dev/null; then
echo "运行 ShellCheck..."
shellcheck "$script_file"
else
echo "ShellCheck 未安装,跳过静态分析"
fi

# 检查常见问题
echo "检查常见问题:"

# 检查未引用的变量
if grep -n '\$[A-Za-z_][A-Za-z0-9_]*' "$script_file" | grep -v '"\$' | grep -v "'\$"; then
echo "⚠ 发现可能未正确引用的变量"
fi

# 检查硬编码路径
if grep -n '\/[a-zA-Z]' "$script_file" | grep -v '#'; then
echo "⚠ 发现硬编码路径"
fi

echo "代码质量检查完成"
}

# 单元测试框架
run_unit_tests() {
echo "=== 单元测试 ==="

# 测试计数器
local tests_run=0
local tests_passed=0

# 断言函数
assert_equals() {
local expected=$1
local actual=$2
local message=${3:-"断言失败"}

((tests_run++))

if [ "$expected" = "$actual" ]; then
echo "✓ $message"
((tests_passed++))
else
echo "✗ $message"
echo " 期望: $expected"
echo " 实际: $actual"
fi
}

assert_not_empty() {
local value=$1
local message=${2:-"值不应为空"}

((tests_run++))

if [ -n "$value" ]; then
echo "✓ $message"
((tests_passed++))
else
echo "✗ $message"
echo " 值为空"
fi
}

# 测试用例
test_string_functions() {
echo "测试字符串函数:"

local result=$(echo "hello" | tr '[:lower:]' '[:upper:]')
assert_equals "HELLO" "$result" "字符串转大写"

local length=${#result}
assert_equals "5" "$length" "字符串长度"
}

test_file_operations() {
echo "测试文件操作:"

local temp_file=$(mktemp)
echo "test content" > "$temp_file"

assert_not_empty "$temp_file" "临时文件创建"

local content=$(cat "$temp_file")
assert_equals "test content" "$content" "文件内容读取"

rm "$temp_file"
}

# 运行测试
test_string_functions
test_file_operations

# 测试结果
echo "========================"
echo "测试结果: $tests_passed/$tests_run 通过"

if [ "$tests_passed" -eq "$tests_run" ]; then
echo "✓ 所有测试通过"
return 0
else
echo "✗ 部分测试失败"
return 1
fi
}

# 性能分析
performance_analysis() {
echo "=== 性能分析 ==="

# CPU使用率监控
monitor_cpu() {
local duration=${1:-10}
echo "监控CPU使用率 $duration 秒..."

for ((i=1; i<=duration; i++)); do
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
echo "时间: ${i}s, CPU: ${cpu_usage}%"
sleep 1
done
}

# 内存使用分析
analyze_memory() {
echo "内存使用分析:"
free -h

echo "进程内存使用 TOP 5:"
ps aux --sort=-%mem | head -6
}

# 磁盘I/O监控
monitor_disk_io() {
if command -v iostat > /dev/null; then
echo "磁盘I/O统计:"
iostat -x 1 3
else
echo "iostat 未安装,跳过磁盘I/O监控"
fi
}

monitor_cpu 5
analyze_memory
monitor_disk_io
}

# 主函数
main() {
local action=${1:-help}

case "$action" in
"debug")
DEBUG=1
debug "调试模式已启用"
;;
"test")
run_unit_tests
;;
"check")
local script_file=${2:-$0}
code_quality_check "$script_file"
;;
"benchmark")
# 创建测试文件
local test_files=()
for i in {1..3}; do
local temp_file=$(mktemp)
seq 1 1000 > "$temp_file"
test_files+=("$temp_file")
done

optimize_file_processing "${test_files[0]}"
parallel_processing_demo "${test_files[@]}"
memory_optimization_demo

# 清理测试文件
rm -f "${test_files[@]}"
;;
"performance")
performance_analysis
;;
"help"|*)
cat << EOF
Shell脚本调试和优化工具

用法: $0 <action> [options]

操作:
debug 启用调试模式
test 运行单元测试
check 代码质量检查
benchmark 性能基准测试
performance 性能分析
help 显示帮助

示例:
$0 debug
$0 test
$0 check script.sh
$0 benchmark
$0 performance
EOF
;;
esac
}

# 执行主函数
main "$@"

总结

Shell脚本编程是Linux系统管理和自动化运维的重要技能。通过本文的学习,我们掌握了从基础语法到高级应用的完整知识体系:

核心要点

  1. 基础语法掌握:变量、条件判断、循环结构是脚本编程的基础
  2. 函数模块化:合理使用函数提高代码复用性和可维护性
  3. 错误处理:完善的错误处理机制确保脚本稳定运行
  4. 性能优化:选择合适的工具和方法提升脚本执行效率
  5. 最佳实践:遵循编码规范,使用调试工具,编写单元测试

实践建议

  1. 从简单开始:先掌握基本语法,再逐步学习高级特性
  2. 多写多练:通过实际项目练习,积累经验
  3. 工具辅助:使用ShellCheck等工具提升代码质量
  4. 文档完善:为脚本添加详细的注释和使用说明
  5. 持续改进:定期回顾和优化现有脚本

Shell脚本编程不仅是技术技能,更是解决实际问题的有力工具。掌握这些技能,将大大提升我们的工作效率和系统管理能力。