Shell脚本入门:自动化处理与系统管理实战

发布时间:2026/9/14 20:40:56
Shell脚本入门:自动化处理与系统管理实战 1. Shell脚本入门从零开始掌握自动化利器作为Linux/Unix系统的核心组件Shell脚本是每位开发者和管理员必备的基础技能。我第一次接触Shell脚本是在处理服务器日志分析时面对每天数百MB的日志文件手动操作效率低下且容易出错。Shell脚本帮我实现了自动化处理从此打开了新世界的大门。Shell脚本本质上是一个包含一系列命令的文本文件它通过Shell解释器如Bash执行。与编译型语言不同Shell脚本无需编译直接解释执行这使得它成为系统管理、文件操作和任务自动化的理想选择。典型的应用场景包括批量文件处理重命名、格式转换定时任务自动化日志轮转、备份系统状态监控CPU/内存报警软件安装部署一键环境配置2. 开发环境准备与基础语法2.1 开发环境配置现代Linux发行版默认都安装了BashBourne Again Shell可以通过以下命令检查$ echo $SHELL /bin/bash $ bash --version GNU bash, version 5.1.16(1)-release推荐使用VS Code作为编辑器安装ShellCheck插件进行语法检查。新建第一个脚本文件#!/bin/bash # 这是我的第一个Shell脚本 echo Hello World!保存为hello.sh后需要添加执行权限chmod x hello.sh ./hello.sh2.2 基础语法要素变量是Shell脚本的基础构建块nameJohn # 定义变量 echo $name # 使用变量 readonly PI3.14 # 只读变量 unset name # 删除变量特殊变量在脚本中非常有用echo 脚本名: $0 echo 第一个参数: $1 echo 参数个数: $# echo 所有参数: $ echo 上条命令结果: $?3. 流程控制与函数3.1 条件判断if语句的基本结构if [ $age -gt 18 ]; then echo 成年人 elif [ $age -gt 12 ]; then echo 青少年 else echo 儿童 fi测试条件常用操作符数值比较-eq, -ne, -gt, -lt字符串比较, !, -z(空)文件测试-e(存在), -d(目录), -r(可读)3.2 循环结构for循环的几种形式# 列表循环 for fruit in apple orange banana; do echo $fruit done # C风格循环 for ((i0; i10; i)); do echo $i done # 遍历参数 for arg in $; do echo $arg donewhile循环示例count1 while [ $count -le 5 ]; do echo Count: $count ((count)) done3.3 函数定义与使用定义和使用函数function greet() { local name$1 # 局部变量 echo Hello, $name return 0 } greet Alice echo 返回值: $?4. 文本处理与正则表达式4.1 常用文本处理工具grep基础用法# 查找包含error的行 grep error log.txt # 忽略大小写 grep -i warning log.txt # 显示行号 grep -n exception log.txtawk实用示例# 打印第一列 awk {print $1} data.txt # 计算列总和 awk {sum$1} END {print sum} numbers.txt # 条件过滤 awk $3 100 {print $0} sales.txtsed流编辑器# 替换文本 sed s/old/new/g file.txt # 删除空行 sed /^$/d file.txt # 原地修改文件 sed -i.bak s/foo/bar/ file.txt4.2 正则表达式基础基本元字符.匹配任意单个字符*前导字符零次或多次^行首锚点$行尾锚点[abc]字符集合\转义特殊字符扩展正则表达式使用-E或egrep前导字符一次或多次?前导字符零次或一次|或操作()分组捕获5. 实战案例解析5.1 日志分析脚本#!/bin/bash # 分析Nginx访问日志 LOG_FILE/var/log/nginx/access.log REPORT_FILEreport_$(date %Y%m%d).txt # 统计总访问量 total$(wc -l $LOG_FILE) # 统计状态码分布 status_codes$(awk {print $9} $LOG_FILE | sort | uniq -c | sort -nr) # 统计访问量前10的IP top_ips$(awk {print $1} $LOG_FILE | sort | uniq -c | sort -nr | head -10) # 生成报告 { echo NGINX访问日志分析报告 echo 生成时间: $(date) echo -------------------------------- echo 总访问量: $total echo echo 状态码分布: echo $status_codes echo echo 访问量前10的IP: echo $top_ips } $REPORT_FILE echo 分析报告已生成: $REPORT_FILE5.2 服务器监控脚本#!/bin/bash # 服务器资源监控告警 THRESHOLD_CPU80 THRESHOLD_MEM90 THRESHOLD_DISK85 ALERT_EMAILadminexample.com # 获取系统指标 cpu_usage$(top -bn1 | grep Cpu(s) | awk {print $2 $4}) mem_usage$(free | awk /Mem/{printf(%.0f), $3/$2*100}) disk_usage$(df -h / | awk NR2{print $5} | tr -d %) # 检查并发送告警 send_alert() { local subject[ALERT] $1 超过阈值 local body当前值: $2% (阈值: $3%) echo $body | mail -s $subject $ALERT_EMAIL } if (( $(echo $cpu_usage $THRESHOLD_CPU | bc -l) )); then send_alert CPU使用率 $cpu_usage $THRESHOLD_CPU fi if [ $mem_usage -gt $THRESHOLD_MEM ]; then send_alert 内存使用率 $mem_usage $THRESHOLD_MEM fi if [ $disk_usage -gt $THRESHOLD_DISK ]; then send_alert 磁盘使用率 $disk_usage $THRESHOLD_DISK fi6. 高级技巧与最佳实践6.1 错误处理与调试set命令用于控制脚本行为set -e # 命令失败时立即退出 set -u # 使用未定义变量时报错 set -x # 打印执行的命令trap捕获信号cleanup() { echo 清理临时文件... rm -f /tmp/temp_* } trap cleanup EXIT INT TERM6.2 性能优化建议减少子进程创建# 不好 - 创建了两个子进程 var$(echo value | tr a-z A-Z) # 好 - 使用内置功能 var${var^^}避免不必要的cat# 不好 cat file.txt | grep pattern # 好 grep pattern file.txt使用here document替代echo# 更清晰的写法 cat EOF config.ini [section] keyvalue EOF6.3 安全注意事项总是引用变量# 危险 - 可能被注入 rm -rf $DIR/* # 安全 rm -rf $DIR/*使用mktemp创建临时文件tempfile$(mktemp /tmp/script.XXXXXX) trap rm -f $tempfile EXIT检查外部命令是否存在command -v jq /dev/null || { echo 错误: jq未安装 2 exit 1 }7. 学习资源与进阶方向7.1 推荐学习资料书籍《Linux命令行与Shell脚本编程大全》《Shell脚本学习指南》《Bash Cookbook》在线资源GNU Bash手册ShellCheck在线检查工具Linux Documentation Project7.2 进阶学习方向正则表达式深度掌握sed/awk高级用法并行处理与进程控制编写可重用的函数库与其他语言集成Python/Perl7.3 常见问题解答Q脚本在Windows编写后Linux无法执行 A使用dos2unix转换行尾符或设置Git不转换git config --global core.autocrlf inputQ如何获取脚本所在目录 A可靠的方法是SCRIPT_DIR$(cd $(dirname ${BASH_SOURCE[0]}) /dev/null pwd -P)Q如何实现跨平台兼容 A使用特性检测而非硬编码路径CMD_SEDsed if [[ $OSTYPE darwin* ]]; then CMD_SEDgsed fi