Shell脚本入门与实战:自动化运维与文本处理

发布时间:2026/9/13 6:42:48
Shell脚本入门与实战:自动化运维与文本处理 1. Shell脚本入门从零开始的自动化之旅第一次接触Shell脚本时我被它的简洁高效所震撼。记得有次需要批量重命名几百个日志文件手动操作简直噩梦而一个简单的for循环脚本3秒就搞定了。Shell脚本就像一把瑞士军刀虽然不如专业编程语言功能强大但在系统管理、文件操作和自动化任务方面它能让你事半功倍。Shell脚本本质上是命令行指令的集合通过特定的语法组织起来实现自动化执行。它特别适合处理文本、管理系统资源和串联多个命令。学习Shell不需要复杂的开发环境任何Linux/Unix系统或Mac的终端都能直接编写运行Windows用户通过WSL或Git Bash也能轻松上手。2. Shell脚本核心语法精要2.1 基础结构解析每个Shell脚本都从shebang开始这个特殊的注释告诉系统用哪个解释器执行脚本。最常见的是#!/bin/bash紧接着是注释以#开头和实际命令。一个完整的脚本示例#!/bin/bash # 这是注释显示当前用户和目录 echo 用户: $USER echo 目录: $(pwd)变量定义和使用是基础中的基础name张三 # 定义变量 echo ${name} # 使用变量注意等号两边不能有空格否则会被视为命令和参数2.2 流程控制实战条件判断是脚本智能化的关键if [ -f /path/to/file ]; then echo 文件存在 elif [ -d /path/to/dir ]; then echo 目录存在 else echo 都不存在 fi循环处理让批量操作成为可能# for循环示例 for i in {1..5}; do echo 第${i}次循环 done # while循环读取文件 while read line; do echo 行内容: $line done filename.txt2.3 函数与参数传递封装重复操作为函数function greet() { local name$1 # local定义局部变量 echo Hello, ${name}! } greet 李四 # 调用函数处理脚本参数echo 脚本名: $0 echo 第一个参数: $1 echo 参数总数: $# echo 所有参数: $3. 实用脚本开发技巧3.1 文件操作大全检查文件属性[ -e file ] # 存在 [ -f file ] # 是普通文件 [ -d dir ] # 是目录 [ -s file ] # 大小0批量重命名我常用的日志处理脚本#!/bin/bash counter1 for file in *.log; do mv $file log_$(date %Y%m%d)_${counter}.log ((counter)) done3.2 文本处理三剑客grep查找内容grep error /var/log/syslog # 查找error关键词 grep -r pattern /some/dir # 递归搜索sed流编辑器sed s/foo/bar/g file.txt # 替换所有foo为bar sed -i.bak 1d file.txt # 删除首行并备份原文件awk数据处理awk {print $1} access.log # 打印第一列 awk -F: {print $1} /etc/passwd # 以:为分隔符3.3 实用脚本片段备份目录带日期压缩#!/bin/bash backup_dir/backups target_dir$HOME/documents [ ! -d $backup_dir ] mkdir -p $backup_dir tar -czf ${backup_dir}/docs_$(date %Y%m%d).tar.gz $target_dir监控磁盘空间报警#!/bin/bash threshold90 usage$(df / | awk NR2 {print $5} | tr -d %) [ $usage -ge $threshold ] mail -s 磁盘告警 adminexample.com 根分区使用率已达${usage}%4. 调试与优化实战4.1 调试技巧使用set命令开启调试模式#!/bin/bash set -x # 开启命令打印 # 你的代码 set x # 关闭调试更专业的调试方法#!/bin/bash -v # 打印读取的命令 #!/bin/bash -x # 打印执行的命令4.2 错误处理防止脚本因错误中断set -e # 任何命令返回非零状态时立即退出 set -o pipefail # 管道命令中任意失败都视为失败 # 或者针对特定命令 command || { echo 命令执行失败 exit 1 }记录日志的最佳实践log() { echo [$(date %Y-%m-%d %H:%M:%S)] $ script.log } log 开始执行任务 important_command || log 命令执行失败 log 任务完成4.3 性能优化减少子进程创建# 差每次循环都启动新进程 for i in {1..100}; do count$(wc -l file.txt) done # 好一次性读取 line_count$(wc -l file.txt) for i in {1..100}; do # 使用$line_count done选择更快的命令替代# 慢 cat file | grep pattern # 快 grep pattern file5. 实际案例服务器监控脚本开发5.1 需求分析开发一个完整的服务器监控脚本需要检查CPU/内存/磁盘使用率监控关键服务状态生成易读的报告支持邮件报警5.2 完整实现#!/bin/bash # 服务器健康监控脚本 # 配置 THRESHOLD_CPU80 THRESHOLD_MEM85 THRESHOLD_DISK90 EMAILadminexample.com LOG_FILE/var/log/health_monitor.log # 初始化日志 log() { echo [$(date %F %T)] $ | tee -a $LOG_FILE } # 检查CPU使用率 check_cpu() { local usage$(top -bn1 | grep Cpu(s) | sed s/.*, *\([0-9.]*\)%* id.*/\1/ | awk {print 100 - $1}) if (( $(echo $usage $THRESHOLD_CPU | bc -l) )); then log CPU使用率过高: ${usage}% return 1 fi return 0 } # 检查内存使用 check_mem() { local total$(free -m | awk /Mem:/ {print $2}) local used$(free -m | awk /Mem:/ {print $3}) local usage$((used*100/total)) if [ $usage -gt $THRESHOLD_MEM ]; then log 内存使用率过高: ${usage}% return 1 fi return 0 } # 检查磁盘空间 check_disk() { local result0 while read line; do local partition$(echo $line | awk {print $1}) local usage$(echo $line | awk {print $5} | tr -d %) if [ $usage -gt $THRESHOLD_DISK ]; then log 磁盘空间告警: ${partition} ${usage}% result1 fi done (df -h | awk NR1 {print $1,$5}) return $result } # 主函数 main() { log 开始服务器健康检查 local alertfalse check_cpu || alerttrue check_mem || alerttrue check_disk || alerttrue if $alert; then mail -s 服务器健康告警 $EMAIL $LOG_FILE log 已发送告警邮件 else log 所有检查项正常 fi } main $5.3 部署建议保存为/usr/local/bin/health_monitor.sh添加执行权限chmod x /usr/local/bin/health_monitor.sh设置cron定时任务# 每30分钟运行一次 */30 * * * * /usr/local/bin/health_monitor.sh日志轮转配置/etc/logrotate.d/health_monitor/var/log/health_monitor.log { daily rotate 7 compress missingok notifempty }6. 进阶学习路径6.1 推荐学习资源书籍《Linux命令行与Shell脚本编程大全》《Shell脚本学习指南》在线文档Bash官方文档man bashGNU Bash手册https://www.gnu.org/software/bash/manual/实战平台OverTheWire Bandit游戏渐进式学习Shell命令Codewars Bash练习挑战脚本编写6.2 常见陷阱与解决方案引号使用问题# 错误文件名含空格时会出错 for file in $(ls); do echo $file done # 正确处理含空格文件名 for file in *; do echo $file done变量未定义检查# 不安全 rm -rf $DIRECTORY/* # 安全做法 : ${DIRECTORY:?未设置目录变量} rm -rf ${DIRECTORY}/*6.3 性能对比测试测试不同循环方式的性能差异# 测试10000次循环 echo 测试for循环: time for ((i0; i10000; i)); do : # 空操作 done echo 测试while循环: time i0; while [ $i -lt 10000 ]; do ((i)) done echo 测试seqfor: time for i in $(seq 1 10000); do : done测试结果通常显示C风格的for循环最快而依赖外部命令的seq最慢。这个简单的测试告诉我们在脚本中尽量减少外部命令调用使用内置语法能显著提高性能。