Shell脚本入门与实战:自动化运维与文本处理
2026/9/13 6:42:41 网站建设 项目流程

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.txt

2.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 counter=1 for file in *.log; do mv "$file" "log_$(date +%Y%m%d)_${counter}.log" ((counter++)) done

3.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 threshold=90 usage=$(df / | awk 'NR==2 {print $5}' | tr -d '%') [ "$usage" -ge "$threshold" ] && mail -s "磁盘告警" admin@example.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" file

5. 实际案例:服务器监控脚本开发

5.1 需求分析

开发一个完整的服务器监控脚本,需要:

  • 检查CPU/内存/磁盘使用率
  • 监控关键服务状态
  • 生成易读的报告
  • 支持邮件报警

5.2 完整实现

#!/bin/bash # 服务器健康监控脚本 # 配置 THRESHOLD_CPU=80 THRESHOLD_MEM=85 THRESHOLD_DISK=90 EMAIL="admin@example.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 result=0 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}%" result=1 fi done < <(df -h | awk 'NR>1 {print $1,$5}') return $result } # 主函数 main() { log "开始服务器健康检查" local alert=false check_cpu || alert=true check_mem || alert=true check_disk || alert=true if $alert; then mail -s "服务器健康告警" $EMAIL < $LOG_FILE log "已发送告警邮件" else log "所有检查项正常" fi } main "$@"

5.3 部署建议

  1. 保存为/usr/local/bin/health_monitor.sh
  2. 添加执行权限:chmod +x /usr/local/bin/health_monitor.sh
  3. 设置cron定时任务:
    # 每30分钟运行一次 */30 * * * * /usr/local/bin/health_monitor.sh
  4. 日志轮转配置(/etc/logrotate.d/health_monitor):
    /var/log/health_monitor.log { daily rotate 7 compress missingok notifempty }

6. 进阶学习路径

6.1 推荐学习资源

  • 书籍:

    • 《Linux命令行与Shell脚本编程大全》
    • 《Shell脚本学习指南》
  • 在线文档:

    • Bash官方文档:man bash
    • GNU 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 ((i=0; i<10000; i++)); do : # 空操作 done echo "测试while循环:" time i=0; while [ $i -lt 10000 ]; do ((i++)) done echo "测试seq+for:" time for i in $(seq 1 10000); do : done

测试结果通常显示C风格的for循环最快,而依赖外部命令的seq最慢。这个简单的测试告诉我们:在脚本中尽量减少外部命令调用,使用内置语法能显著提高性能。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询