Shell 脚本从入门到写出第一个自动化脚本
—title: Shell 脚本从入门到写出第一个自动化脚本date: 2026-06-26tags: [shell, bash, 自动化脚本]series: CSDN知识付费—# Shell 脚本从入门到写出第一个自动化脚本## 开篇引言在 Linux/Unix 的世界里,Shell 脚本是运维工程师和开发者的必备技能。无论是部署服务、批量处理文件、定时任务,还是监控系统状态,Shell 脚本都能让你的工作效率提升数倍。不要觉得写脚本很神秘,其实它就是把你在终端里手动敲的命令,按顺序写进一个文件里。今天,我们就从零开始,一步步写出属于你的第一个实用自动化脚本。>适用人群:有 Linux 基础操作经验(会 ls、cd、vim)的开发者或运维新人。## 核心概念### 什么是 Shell 脚本Shell 脚本是用于命令行解释器(如 Bash)的一系列命令的集合。它会逐行执行你写好的指令。### 为什么是 BashBash(Bourne Again Shell)是绝大多数 Linux 发行版的默认 shell,兼容性好、功能强大。本教程所有示例均基于Bash。### 脚本的执行流程bash# 1. 创建文件touch my_script.sh# 2. 写入代码(用 vim 或 echo)# 3. 添加执行权限chmod +x my_script.sh# 4. 执行脚本./my_script.sh关键点:第一行#!/bin/bash是shebang,告诉系统用什么解释器执行脚本。## 实战操作(6个必备示例 + 2个自动化脚本)### 示例 1:Hello World + 变量bash#!/bin/bash# 第一个脚本:变量定义与输出NAME="Linux运维实战"echo "Hello, $NAME"echo "当前时间: $(date)"echo "当前用户: $USER"# 数字计算a=10b=20sum=$((a + b))echo "10 + 20 = $sum"输出结果:Hello, Linux运维实战当前时间: Mon Mar 17 10:30:22 CST 2025当前用户: root10 + 20 = 30>注意:变量赋值=两边不能有空格,否则会报错。### 示例 2:条件判断与循环bash#!/bin/bash# 判断文件是否存在 + 遍历目录TARGET_FILE="/tmp/test.txt"# 条件判断:-f 检测是否为文件if [ -f "$TARGET_FILE" ]; then echo "文件 $TARGET_FILE 存在"else echo "文件不存在,正在创建..." touch "$TARGET_FILE" echo "创建成功"fi# for 循环遍历当前目录下的 .sh 文件echo ""echo "=== 当前目录下的 Shell 脚本 ==="for file in *.sh; do if [ -f "$file" ]; then echo " - $file ($(wc -l < "$file") 行)" fidone输出结果:文件不存在,正在创建...创建成功=== 当前目录下的 Shell 脚本 === - my_script.sh (5 行)### 示例 3:函数定义与参数传递bash#!/bin/bash# 定义函数:计算文件大小(人性化显示)human_readable_size() { local bytes=$1 if [ $bytes -lt 1024 ]; then echo "${bytes}B" elif [ $bytes -lt 1048576 ]; then echo "$((bytes / 1024))KB" else echo "$((bytes / 1048576))MB" fi}# 调用函数FILE_PATH="/var/log/syslog"if [ -f "$FILE_PATH" ]; then SIZE=$(stat -c%s "$FILE_PATH") echo "$FILE_PATH 的大小为: $(human_readable_size $SIZE)"fi输出结果:/var/log/syslog 的大小为: 128KB### 示例 4:读取文件内容并处理bash#!/bin/bash# 逐行读取 /etc/passwd,提取用户名和 shellecho "用户名 | 登录Shell"echo "-----------------"while IFS=: read -r username _ uid gid _ home shell; do # 只显示 uid >= 1000 的普通用户 if [ "$uid" -ge 1000 ] 2>/dev/null; then printf "%-10s | %s\n" "$username" "$shell" fidone < /etc/passwd输出结果:用户名 | 登录Shell-----------------nobody | /usr/sbin/nologintestuser | /bin/bash### 示例 5:错误处理与退出码bash#!/bin/bashset -e # 发生任何错误立即退出cleanup() { echo "脚本被中断,正在清理..." rm -f /tmp/temp_data_*.txt exit 1}trap cleanup SIGINT SIGTERMecho "开始执行安全操作..."# 模拟可能失败的操作mkdir -p /backup || { echo "创建备份目录失败"; exit 1; }# 使用 && 和 || 控制流程ping -c 1 8.8.8.8 &>/dev/null && echo "网络可达" || echo "网络不可达"echo "操作完成,退出码: $?" # 使用 $? 获取上一条命令的退出码输出结果(正常情况):开始执行安全操作...网络可达操作完成,退出码: 0### 示例 6:日志记录与时间戳bash#!/bin/bashLOG_FILE="/var/log/auto_deploy.log"log_info() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $1" | tee -a "$LOG_FILE"}log_error() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1" | tee -a "$LOG_FILE" >&2}log_info "脚本启动"# 模拟部署过程sleep 1log_info "下载依赖包完成"sleep 0.5log_info "配置文件已更新"# 模拟错误if [ ! -d "/nonexistent" ]; then log_error "目录 /nonexistent 不存在"filog_info "脚本完成"### 完整自动化脚本 1:批量重命名文件bash#!/bin/bash# 功能:将当前目录下的所有 .txt 文件重命名为 日期_原文件名.txtTARGET_EXT="txt"TODAY=$(date +%Y%m%d)COUNT=0echo "开始批量重命名 .$TARGET_EXT 文件..."for file in *."$TARGET_EXT"; do if [ -f "$file" ]; then NEW_NAME="${TODAY}_${file}" mv "$file" "$NEW_NAME" echo " ✓ $file -> $NEW_NAME" ((COUNT++)) fidoneif [ "$COUNT" -eq 0 ]; then echo "未找到 .$TARGET_EXT 文件"else echo "✅ 成功重命名 $COUNT 个文件"fi执行效果:开始批量重命名 .txt 文件... ✓ notes.txt -> 20250317_notes.txt ✓ config.txt -> 20250317_config.txt✅ 成功重命名 2 个文件### 完整自动化脚本 2:系统健康检查bash#!/bin/bash# 功能:检查 CPU、内存、磁盘、进程数,异常时发送告警THRESHOLD_CPU=80 # CPU 使用率阈值(%)THRESHOLD_MEM=90 # 内存使用率阈值(%)THRESHOLD_DISK=85 # 磁盘使用率阈值(%)ALERT_EMAIL="admin@example.com"ALERT_LOG="/var/log/system_alert.log"get_cpu_usage() { # 取 1 分钟内的平均 CPU 使用率(留一个核心做空闲参考) top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}' | cut -d. -f1}get_mem_usage() { free | grep Mem | awk '{printf "%.0f", $3/$2 * 100}'}get_disk_usage() { df / | tail -1 | awk '{print $5}' | tr -d '%'}# 收集数据CPU=$(get_cpu_usage)MEM=$(get_mem_usage)DISK=$(get_disk_usage)PROC_COUNT=$(ps aux --no-headers | wc -l)# 检测异常ALERT_MSG=""[ "$CPU" -gt "$THRESHOLD_CPU" ] && ALERT_MSG+="CPU 使用率过高: ${CPU}% (阈值: ${THRESHOLD_CPU}%)\n"[ "$MEM" -gt "$THRESHOLD_MEM" ] && ALERT_MSG+="内存使用率过高: ${MEM}% (阈值: ${THRESHOLD_MEM}%)\n"[ "$DISK" -gt "$THRESHOLD_DISK" ] && ALERT_MSG+="磁盘使用率过高: ${DISK}% (阈值: ${THRESHOLD_DISK}%)\n"# 输出报告echo "========== 系统健康报告 $(date) =========="echo "CPU 使用率: ${CPU}%"echo "内存使用率: ${MEM}%"echo "磁盘使用率: ${DISK}%"echo "进程数: ${PROC_COUNT}"if [ -n "$ALERT_MSG" ]; then echo -e "\n⚠️ 异常告警:" echo -e "$ALERT_MSG" # 写入日志(实际环境可发送邮件) echo "[$(date)] 告警: $ALERT_MSG" >> "$ALERT_LOG"else echo "✅ 系统状态正常"fi输出结果:========== 系统健康报告 Mon Mar 17 10:35:00 CST 2025 ==========CPU 使用率: 23%内存使用率: 45%磁盘使用率: 67%进程数: 189✅ 系统状态正常## 常见坑和解决方案### 坑 1:if [ $var = "value" ]变量为空时报错错误示例:bashvar=""if [ $var = "hello" ]; then # 展开后变成 if [ = "hello" ],语法错误 echo "equal"fi✅ 正确做法:bash# 方案一:变量加双引号if [ "$var" = "hello" ]; then echo "equal"fi# 方案二:使用 [[ ]] 增强语法(支持正则)if [[ $var == "hello" ]]; then echo "equal"fi### 坑 2:for file in *.log没有匹配文件时执行一次错误现象:bashfor file in *.log; do echo "处理 $file"done# 如果没有 .log 文件,会输出 "处理 *.log"✅ 正确做法:bash# 先检查是否有匹配文件shopt -s nullglob # 启用 nullglob 选项,没有匹配返回空for file in *.log; do [ -f "$file" ] || continue # 跳过空值 echo "处理 $file"doneshopt -u nullglob # 恢复默认### 坑 3:$(( ... ))做浮点数运算失败错误示例:bashecho $((3 / 2)) # 输出 1(整数运算)✅ 正确做法:bash# 方案一:使用 bcecho "scale=2; 3/2" | bc # 输出 1.50# 方案二:使用 awkawk "BEGIN {printf \"%.2f\n\", 3/2}" # 输出 1.50## 总结通过本文,你应该已经掌握了以下核心技能:| 知识点 | 对应示例 | 实用程度 ||--------|----------|----------|| 变量与字符串处理 | 示例1 | ⭐⭐⭐⭐⭐ || 条件判断与循环 | 示例2 | ⭐⭐⭐⭐⭐ || 函数封装 | 示例3 | ⭐⭐⭐⭐ || 文件读写与流处理 | 示例4 | ⭐⭐⭐⭐ || 错误处理与信号捕获 | 示例5 | ⭐⭐⭐⭐ || 日志记录与调试 | 示例6 | ⭐⭐⭐⭐⭐ ||自动化实践| 批量重命名、系统巡检 |⭐必看|**核心要点回顾:**1.写好 shebang:#!/bin/bash2.变量加引号:避免空格和空值问题3.用set -e和trap:增强脚本健壮性4.善用tee和>>:记录日志5.写自动化脚本前先手动执行一次:确认逻辑正确从现在开始,把重复操作写成脚本。比如每天备份数据库、定时清理日志、批量修改配置文件——自动化的价值,会在你喝杯咖啡的时间里体现出来。## 推荐阅读1. Linux 三剑客:grep、sed、awk 实战指南 —— 文本处理神器的 20 个高频用法2. Crontab 定时任务从小白到高手 —— 让你的脚本在凌晨自动运行3. Shell 脚本调试技巧与性能优化 —— 解决脚本跑起来慢、找 bug 难的问题