从手动删日志到自动化运维:我用7天掌握Shell脚本,解放30%工作时间

去年做 Linux 运维时,有个任务让我每天崩溃 —— 手动清理 10 台服务器的日志文件。每天早上,我要登录每台机器,执行cd /var/logrm -rf *.log.1tar -zcvf nginx.log.tar.gz nginx.log,一套操作下来,1 小时就没了。

有次因为加班忘了清理,某台服务器日志占满磁盘,导致业务中断,被领导批评时,我忍不住想:“有没有办法让这些操作自动跑?”

就在这时,同事扔给我一个文件,说:“试试这个 Shell 脚本,双击就能搞定所有机器的日志清理。” 我打开文件,里面是几行看似简单的代码,却包含了登录、执行命令、压缩文件的全流程。运行后,原本 1 小时的工作,3 分钟就完成了。

那是我第一次意识到:Shell 脚本不是 “程序员的专属工具”,而是每个 Linux 使用者的 “自动化利器”。后来我花 7 天系统学完 Shell 基础,把 “手动部署服务”“批量创建用户”“监控磁盘空间” 等重复任务全改成了脚本,工作效率直接提升 30%。

这篇文章,我会用 “零基础能看懂” 的语言,拆解 Shell 脚本的核心知识,再通过 3 个实战案例,帮你快速掌握 “用脚本解放双手” 的能力。

一、先搞懂:什么是 Shell 脚本?它为什么能 “自动化”?

很多人觉得 Shell 脚本 “高深”,其实它的本质特别简单 —— 就像把你在 Linux 终端里敲的命令,按顺序写进一个文件里,让系统 “按剧本执行”。

1. 一句话说清:Shell 与 Shell 脚本的关系

我们可以把 Linux 系统比作 “一家餐厅”:

  • 内核:后厨,负责真正的 “做菜”(执行底层操作,如读写磁盘、网络通信);
  • Shell:服务员,是你和后厨的 “翻译官”—— 你说 “来份宫保鸡丁”(输入命令),服务员传给后厨,再把做好的菜(执行结果)端给你;
  • Shell 脚本:你提前写好的 “点餐清单”,把 “宫保鸡丁、米饭、可乐” 按顺序列好,服务员直接按清单下单,不用你重复开口。

简单来说:Shell 是 “命令解释器”,Shell 脚本是 “多个 Shell 命令的集合文件”,通过脚本,你可以让系统自动执行一系列操作,不用手动敲命令。

2. Shell 脚本的 3 个核心优势:为什么运维 / 开发都离不开它?

  • 自动化重复工作:像日志清理、文件备份、服务部署这类 “每天都要做” 的操作,写一次脚本,后续双击就能执行;
  • 跨机器批量操作:结合ssh命令,一个脚本能同时控制 10 台、100 台 Linux 机器,不用逐台登录;
  • 学习成本低:语法接近 Linux 命令,不用像学 Python、Java 那样记复杂的类和函数,零基础 7 天就能上手实战。

3. 常见的 Shell 类型:我们该学哪一种?

Linux 里有多种 Shell(如 sh、bash、zsh),其中bash(Bourne Again Shell) 是最常用的,默认安装在 99% 的 Linux 系统(CentOS、Ubuntu、Debian)里,也是我们要学的重点。

判断你的系统是否支持 bash,只需在终端输入echo $SHELL,如果输出/bin/bash,就说明可以直接写 bash 脚本。

二、快速上手:从 “环境准备” 到 “基础语法”,7 天搞定核心知识

零基础学 Shell 脚本,不用贪多求全,先掌握 “能写出实用脚本” 的核心语法即可。我把 7 天的学习计划拆解成 “环境准备→基本要素→核心语法” 三部分,每部分都配 “代码示例 + 运行效果”,跟着做就能学会。

1. 第 1 天:环境准备 ——3 步写出第一个 Shell 脚本

写 Shell 脚本不需要复杂工具,终端 + 文本编辑器(如 vim、nano)就能搞定,全程 3 步:

步骤 1:创建脚本文件

在终端输入vim auto_clean_log.sh,创建一个名为 “auto_clean_log.sh” 的脚本文件(.sh是 Shell 脚本的默认后缀,方便识别)。

步骤 2:写脚本内容(第一个 “Hello World”)

在 vim 里输入以下内容,这是最基础的 Shell 脚本结构:

#!/bin/bash
# 这是我的第一个Shell脚本(#开头的是注释,不会被执行)
echo "开始执行日志清理脚本..."  # echo命令:在终端输出文字
date  # 输出当前时间,方便查看脚本执行时间
  • #!/bin/bash指定解释器,告诉系统用 bash 来执行这个脚本(必须写在第一行);
  • # 注释内容:用来解释脚本功能,方便自己或别人看懂,系统会忽略注释;
  • echo "文字":输出文字到终端,相当于 “打印日志”,方便跟踪脚本执行过程。
步骤 3:赋予权限并运行

Shell 脚本默认没有 “执行权限”,需要先授权,再运行:

# 步骤1:赋予执行权限(chmod +x 文件名:给文件增加“执行”权限)
chmod +x auto_clean_log.sh

# 步骤2:运行脚本(两种方式)
./auto_clean_log.sh  # 方式1:./表示“当前目录”,推荐用这种,避免和系统命令重名
bash auto_clean_log.sh  # 方式2:直接用bash解释器运行,不用提前授权
运行效果:

终端会输出:

开始执行日志清理脚本...
2024年 05月 20日 星期一 14:30:00 CST

到这里,你已经写出并运行了第一个 Shell 脚本!是不是比想象中简单?

2. 第 2-3 天:核心语法 —— 掌握这 4 个要素,能写 80% 实用脚本

Shell 脚本的语法不复杂,重点掌握 “变量、条件判断、循环、函数” 这 4 个要素,就能应对大部分自动化场景。

(1)变量:存储数据,让脚本更灵活

变量就像 “小盒子”,用来存数字、文字、命令结果,方便后续调用。比如你想让脚本 “清理指定目录的日志”,就可以用变量存 “目录路径”,后续改路径时不用改整个脚本。

常用变量用法示例

#!/bin/bash
# 1. 定义变量(格式:变量名=值,注意:=前后不能有空格!这是新手最常踩的坑)
LOG_DIR="/var/log"  # 定义“日志目录”变量,存日志文件的路径
BACKUP_DIR="/var/backup/log"  # 定义“备份目录”变量,存压缩后的日志
CURRENT_DATE=$(date +%Y%m%d)  # 定义“当前日期”变量,$(命令)表示“执行命令并把结果存到变量里”

# 2. 使用变量(格式:$变量名 或 ${变量名},{}可选,推荐用${},避免歧义)
echo "日志目录:${LOG_DIR}"
echo "备份目录:${BACKUP_DIR}"
echo "当前日期:${CURRENT_DATE}"

# 3. 特殊变量:系统自带的变量,不用定义就能用
echo "脚本文件名:$0"  # $0:当前脚本的文件名
echo "传入的第一个参数:$1"  # $1:运行脚本时传入的第一个参数(比如./script.sh 123,$1就是123)
echo "传入的参数总数:$#"  # $#:运行脚本时传入的参数总数

运行效果(执行./test_var.sh 20240520):

日志目录:/var/log
备份目录:/var/backup/log
当前日期:20240520
脚本文件名:./test_var.sh
传入的第一个参数:20240520
传入的参数总数:1
(2)条件判断:让脚本 “会做选择”

条件判断用来实现 “如果满足 A 条件,就执行 B 操作;否则执行 C 操作”。比如 “如果日志文件存在,就压缩备份;否则提示文件不存在”。

核心语法(if-else)

#!/bin/bash
LOG_FILE="/var/log/nginx.log"  # 要判断的日志文件

# 条件判断格式:if [ 条件表达式 ]; then 操作; else 操作; fi(fi表示结束)
# 注意:[ 和 ] 前后必须有空格!否则会报错
if [ -f "${LOG_FILE}" ]; then  # -f:判断文件是否存在且是普通文件
    echo "找到日志文件:${LOG_FILE},开始压缩备份..."
    tar -zcvf "${LOG_FILE}_${CURRENT_DATE}.tar.gz" "${LOG_FILE}"  # 压缩文件
else
    echo "错误:未找到日志文件 ${LOG_FILE}"
fi

常用条件表达式(记这几个足够用):

表达式含义示例
-f 文件判断文件是否存在且是普通文件[ -f /var/log/nginx.log ]
-d 目录判断目录是否存在[ -d /var/backup ]
-n 字符串判断字符串是否非空[ -n “$LOG_FILE” ]
$a -eq $b判断 a 和 b 是否相等(数字)[ $1 -eq 100 ]
$a -gt $b判断 a 是否大于 b(数字)[ $disk_usage -gt 80 ]
(3)循环:让脚本 “重复做一件事”

循环用来实现 “重复执行某段操作”,比如 “批量清理 10 个目录的日志”“给 5 个用户设置密码”。最常用的是for循环和while循环。

示例 1:for 循环 —— 批量处理文件

#!/bin/bash
# 批量清理/var/log下所有.log.1后缀的日志文件
LOG_DIR="/var/log"

# for循环格式:for 变量 in 列表; do 操作; done
for log_file in $(ls "${LOG_DIR}"/*.log.1); do  # ls ${LOG_DIR}/*.log.1:列出所有.log.1文件
    echo "正在删除旧日志:${log_file}"
    rm -rf "${log_file}"  # 删除旧日志
done
echo "批量清理完成!"

示例 2:while 循环 —— 按条件重复执行

#!/bin/bash
# 监控磁盘使用率,当使用率超过80%时报警
disk_usage=$(df -h / | grep / | awk '{print $5}' | sed 's/%//g')  # 获取根目录使用率(数字)

# while循环格式:while [ 条件 ]; do 操作; done
while [ ${disk_usage} -gt 80 ]; do  # 当使用率>80%时,持续报警
    echo "警告:磁盘使用率已达 ${disk_usage}%,请及时清理!"
    sleep 60  # 暂停60秒后再次检查
    disk_usage=$(df -h / | grep / | awk '{print $5}' | sed 's/%//g')  # 重新获取使用率
done
echo "磁盘使用率正常:${disk_usage}%"
(4)函数:把重复代码 “打包”,让脚本更简洁

如果脚本里有 “多次重复的操作”,可以把这些操作封装成 “函数”,像调用命令一样调用,减少代码冗余。

函数示例 —— 封装 “日志备份” 操作

#!/bin/bash
CURRENT_DATE=$(date +%Y%m%d)

# 定义函数(格式:函数名() { 操作; })
backup_log() {
    local log_file=$1  # local:定义局部变量,只在函数内有效;$1:函数的第一个参数
    local backup_dir=$2  # $2:函数的第二个参数
    
    echo "开始备份:${log_file}"
    # 先判断备份目录是否存在,不存在则创建
    if [ ! -d "${backup_dir}" ]; then  # !:否定,-d:判断目录
        mkdir -p "${backup_dir}"  # -p:创建多级目录
    fi
    # 压缩备份
    tar -zcvf "${backup_dir}/$(basename ${log_file})_${CURRENT_DATE}.tar.gz" "${log_file}"
}

# 调用函数(格式:函数名 参数1 参数2)
backup_log "/var/log/nginx.log" "/var/backup/log"
backup_log "/var/log/mysql.log" "/var/backup/log"
echo "所有日志备份完成!"

3. 第 4-7 天:脚本调试 —— 新手必学的 “排错技巧”

写脚本时难免出错,比如语法错误、路径错误,掌握调试技巧能帮你快速定位问题。

(1)查看语法错误

在终端执行bash -n 脚本名.sh,bash 会检查脚本的语法是否正确,比如少写fi=前后有空格等错误:

bash -n auto_clean_log.sh  # 无输出表示语法正确,有错误会提示位置
(2)跟踪执行过程

执行bash -x 脚本名.sh,bash 会逐行输出脚本的执行过程,包括 “执行了哪个命令”“变量的值是什么”,方便定位哪一步出错:

bash -x auto_clean_log.sh
# 输出示例(+开头的是执行的命令,不带+的是echo输出)
+ CURRENT_DATE=20240520
+ backup_log /var/log/nginx.log /var/backup/log
+ local log_file=/var/log/nginx.log
+ local backup_dir=/var/backup/log
+ echo 开始备份:/var/log/nginx.log
开始备份:/var/log/nginx.log
(3)输出错误日志

在脚本里用echo "错误信息" >&2,把错误信息输出到 “标准错误流”,方便后续查看错误记录:

if [ ! -f "${LOG_FILE}" ]; then
    echo "错误:未找到日志文件 ${LOG_FILE}" >&2  # >&2:把输出重定向到错误流
    exit 1  # exit 1:脚本异常退出,告诉调用者“脚本执行失败”
fi

三、实战 3 案例:从 “理论” 到 “落地”,脚本直接能用

学完基础语法后,一定要用实战案例巩固。下面 3 个案例是我日常工作中常用的脚本,你可以直接复制修改后使用。

案例 1:日志自动清理 + 备份脚本(每天执行)

需求:每天凌晨 2 点,清理 /var/log 下 3 天前的.log.1 旧日志,备份当天的 nginx.log 和 mysql.log 到 /var/backup/log,并输出执行日志到 /var/log/auto_backup.log。

完整脚本(auto_backup_log.sh)

#!/bin/bash
# 日志自动清理+备份脚本
# 运行方式:1. 手动执行 ./auto_backup_log.sh;2. 加入crontab定时执行

# 1. 定义变量
LOG_DIR="/var/log"
BACKUP_DIR="/var/backup/log"
CURRENT_DATE=$(date +%Y%m%d)
LOG_FILE="${LOG_DIR}/auto_backup.log"  # 脚本自身的执行日志
KEEP_DAYS=3  # 旧日志保留天数

# 2. 函数:输出日志(带时间戳)
write_log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> "${LOG_FILE}"  # >>:追加日志到文件
}

# 3. 开始执行
write_log "=== 开始执行日志备份脚本 ==="

# 3.1 备份当天的nginx.log和mysql.log
for log_name in "nginx.log" "mysql.log"; do
    full_log_path="${LOG_DIR}/${log_name}"
    if [ -f "${full_log_path}" ]; then
        write_log "正在备份日志:${full_log_path}"
        tar -zcf "${BACKUP_DIR}/${log_name}_${CURRENT_DATE}.tar.gz" "${full_log_path}"
        if [ $? -eq 0 ]; then  # $?:上一个命令的执行结果(0=成功,非0=失败)
            write_log "备份成功:${BACKUP_DIR}/${log_name}_${CURRENT_DATE}.tar.gz"
        else
            write_log "错误:备份 ${full_log_path} 失败" >&2
        fi
    else
        write_log "警告:未找到日志文件 ${full_log_path}" >&2
    fi
done

# 3.2 清理3天前的.log.1旧日志
write_log "开始清理${KEEP_DAYS}天前的旧日志..."
find "${LOG_DIR}" -name "*.log.1" -mtime +${KEEP_DAYS} -exec rm -rf {} \;  # -mtime +3:3天前的文件
write_log "旧日志清理完成"

write_log "=== 脚本执行结束 ==="
echo "脚本执行完成,日志查看:${LOG_FILE}"

定时执行:用crontab设置每天凌晨 2 点运行(Linux 定时任务工具):

# 编辑定时任务
crontab -e

# 在文件末尾添加以下内容(含义:每天2点0分执行脚本)
0 2 * * * /root/scripts/auto_backup_log.sh  # 脚本路径要写绝对路径

案例 2:批量创建 Linux 用户脚本

需求:为新入职的 5 个员工创建 Linux 账号,用户名分别为 user1-user5,初始密码为 “Company@2024”,并赋予 sudo 权限。

完整脚本(batch_create_user.sh)

#!/bin/bash
# 批量创建用户脚本
# 运行方式:sudo ./batch_create_user.sh(创建用户需要root权限)

# 1. 检查是否为root用户(创建用户必须root权限)
if [ "$(whoami)" != "root" ]; then  # whoami:获取当前用户名
    echo "错误:请用root权限运行(sudo ./batch_create_user.sh)" >&2
    exit 1
fi

# 2. 定义变量
USER_PREFIX="user"  # 用户名前缀
USER_NUM=5  # 要创建的用户数量
INIT_PWD="Company@2024"  # 初始密码

# 3. 批量创建用户
for ((i=1; i<=${USER_NUM}; i++)); do
    username="${USER_PREFIX}${i}"
    # 先判断用户是否已存在
    if id -u "${username}" >/dev/null 2>&1; then  # id -u:检查用户是否存在,>/dev/null 2>&1:隐藏输出
        echo "警告:用户 ${username} 已存在,跳过创建"
        continue  # 跳过当前循环,继续下一个
    fi
    # 创建用户(-m:创建用户家目录,-s:指定默认Shell为/bin/bash)
    useradd -m -s /bin/bash "${username}"
    # 设置密码(echo "密码" | passwd --stdin 用户名:非交互式设置密码)
    echo "${INIT_PWD}" | passwd --stdin "${username}"
    # 赋予sudo权限(把用户加入wheel组,CentOS默认wheel组有sudo权限)
    usermod -aG wheel "${username}"
    
    if [ $? -eq 0 ]; then
        echo "成功创建用户:${username},初始密码:${INIT_PWD}(请提醒用户首次登录修改密码)"
    else
        echo "错误:创建用户 ${username} 失败" >&2
    fi
done
echo "批量创建用户完成!"

案例 3:磁盘使用率监控报警脚本

需求:每 30 分钟检查一次根目录(/)的磁盘使用率,当使用率超过 80% 时,发送邮件提醒管理员。

完整脚本(monitor_disk.sh)

#!/bin/bash
# 磁盘使用率监控报警脚本
# 依赖:需要安装mailx工具(CentOS:yum install -y mailx;Ubuntu:apt install -y mailutils)

# 1. 定义变量
MONITOR_DIR="/"  # 要监控的目录(根目录)
THRESHOLD=80  # 报警阈值(80%)
ADMIN_EMAIL="admin@example.com"  # 管理员邮箱
CURRENT_TIME=$(date +'%Y-%m-%d %H:%M:%S')

# 2. 获取磁盘使用率(数字)
# df -h /:查看根目录磁盘信息;grep /:过滤根目录行;awk '{print $5}':取第5列(使用率,如85%);sed 's/%//g':去掉%
disk_usage=$(df -h "${MONITOR_DIR}" | grep "${MONITOR_DIR}" | awk '{print $5}' | sed 's/%//g')

# 3. 判断是否超过阈值,超过则发邮件
if [ ${disk_usage} -gt ${THRESHOLD} ]; then
    # 邮件主题和内容
    subject="【警告】${MONITOR_DIR} 磁盘使用率超过${THRESHOLD}%"
    content="
    监控时间:${CURRENT_TIME}
    监控目录:${MONITOR_DIR}
    当前使用率:${disk_usage}%
    报警阈值:${THRESHOLD}%
    建议:请及时清理无用文件(如旧日志、备份文件),避免磁盘占满导致业务中断。
    "
    # 发送邮件(echo 内容 | mail -s 主题 收件人)
    echo -e "${content}" | mail -s "${subject}" "${ADMIN_EMAIL}"
    echo "[$CURRENT_TIME] 警告:磁盘使用率${disk_usage}%,已发送邮件提醒管理员"
else
    echo "[$CURRENT_TIME] 正常:磁盘使用率${disk_usage}%,低于阈值${THRESHOLD}%"
fi

四、新手避坑指南:我踩过的 5 个经典错误

  1. 变量赋值有空格:比如LOG_DIR = "/var/log"(错误),正确是LOG_DIR="/var/log"——=前后不能有空格,否则系统会把 “LOG_DIR” 当成命令。
  2. 条件判断缺空格:比如if [-f "${LOG_FILE}"](错误),正确是if [ -f "${LOG_FILE}" ]——[]前后必须有空格,这是 bash 的语法要求。
  3. 路径用相对路径:比如./auto_clean.sh里写rm -rf log/*.log,如果在其他目录执行脚本,会找不到 “log” 目录 —— 正确是用绝对路径,如rm -rf /var/log/*.log
  4. 不判断命令执行结果:比如直接执行tar -zcvf ...,不检查是否备份成功 —— 正确是用if [ $? -eq 0 ]判断上一步是否成功,避免失败了还不知道。
  5. 忽略权限问题:比如创建用户脚本不用 root 权限运行,导致useradd命令报错 —— 正确是用sudo运行需要高权限的脚本。

结语:Shell 脚本的核心,是 “解放你的双手”

很多人学 Shell 脚本时,会陷入 “追求复杂语法” 的误区,其实 Shell 的核心价值是 “自动化重复工作”—— 哪怕是只有 10 行的简单脚本,只要能帮你节省时间,就是好脚本。

我刚开始学的时候,也只会写 “清理日志”“备份文件” 这类简单脚本,但正是这些脚本,帮我从每天重复敲命令的枯燥工作中解放出来,有更多时间学习其他技能。

记住:学习 Shell 脚本不用 “一步到位”,先从解决自己的实际问题开始 —— 比如你每天要手动备份文件,就写个备份脚本;每天要检查服务状态,就写个监控脚本。多练、多改,7 天就能上手,1 个月就能熟练,3 个月就能写出能落地的自动化脚本。

现在,打开你的 Linux 终端,试着写一个 “自动备份你工作目录” 的脚本吧 —— 从实践中学习,才是最快的方式!

网络安全学习资源分享:

给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

因篇幅有限,仅展示部分资料,朋友们如果有需要全套《网络安全入门+进阶学习资源包》,请看下方扫描即可前往获取

在这里插入图片描述
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值