← 回目录
27 Week 06 · 脚本与收尾

条件和循环

今天把明天那个巡检脚本的所有零件配齐:if 判断阈值、for 遍历服务、awk 取字段。

if 判断

基本结构
#!/bin/bash
USE=85

if [ "$USE" -gt 80 ]; then
    echo "磁盘告警:已用 ${USE}%"
elif [ "$USE" -gt 60 ]; then
    echo "注意:已用 ${USE}%"
else
    echo "正常:${USE}%"
fi
四个容易错的地方
方括号两边要有空格
[ "$USE" -gt 80 ] ✅ ——[ 后面和 ] 前面必须有空格["$USE"-gt 80] ❌ 会报错。
then 前面要有分号
if [ ... ]; then,或者把 then 写到下一行。
结尾是 fi
if 倒过来写。同理 case 结尾是 esac
变量加双引号
"$USE" 而不是 $USE——变量为空时不加引号会导致语法错误。

比较运算符

数字和字符串不一样
别用混了
数字比较
-eq 等于 -ne 不等于 -gt 大于 -lt 小于 -ge 大于等于 -le 小于等于
字符串比较
= 相等 != 不等 -z 是空字符串 -n 非空
常见错误
数字用 > 会被当成重定向——[ $a > $b ] 会创建一个叫 $b 的文件!数字一定用 -gt
文件测试(很常用)
if [ -f /etc/nginx/nginx.conf ]; then   # -f 文件存在
if [ -d /var/log ]; then                # -d 目录存在
if [ -x /opt/check.sh ]; then           # -x 有执行权限
if [ ! -f /tmp/lock ]; then             # ! 取反
if [ -z "$VAR" ]; then                  # -z 变量为空
一个实用模式

脚本开头检查依赖,缺什么直接退出,比跑到一半才失败好:

[ -f /opt/config ] || { echo "配置文件不存在"; exit 1; }

for 循环

遍历列表(最常用)
for svc in sshd nginx crond; do
    if systemctl is-active --quiet "$svc"; then
        echo "$svc 正常"
    else
        echo "$svc 异常"
    fi
done
另外两种写法
# 遍历文件
for f in /etc/*.conf; do
    echo "找到配置:$f"
done

# 数字范围
for i in {1..5}; do
    echo "第 $i 次"
done

while read:逐行处理

处理命令输出的标准姿势
读取每一行
# 逐行读文件
while read -r line; do
    echo "这一行是:$line"
done < /etc/hosts

# 处理命令的输出(注意管道写法)
df -h | grep -v Filesystem | while read -r line; do
    echo "$line"
done

read -r-r 表示不转义反斜杠,读文件时基本都该加上。

awk:取出某一列

先会用,不用深究

awk 功能极强,但运维日常九成场景只用到一件事:按列取值。今天只学这个。

$1 $2 $3 是第几列
$ df -h /
Filesystem           Size  Used Avail Use% Mounted on
/dev/mapper/rl-root   62G   12G   50G  20% /
     $1        $2    $3    $4   $5   $6

# 取第 5 列(使用率)
$ df -h / | awk 'NR==2 {print $5}'
20%
这条命令拆开看
NR==2
只处理第 2 行(NR = Number of Record,行号)。因为第 1 行是表头。
{print $5}
打印第 5 个字段。字段默认按空格分隔。
单引号
必须单引号——昨天说过,双引号的话 $5 会被 shell 先解释掉。
几个直接能用的
# 磁盘使用率(去掉百分号,变成纯数字好比较)
$ df -h / | awk 'NR==2 {print $5}' | tr -d '%'
20

# 内存使用百分比
$ free -m | awk 'NR==2 {printf "%.1f\n", $3/$2*100}'
31.4

# 带条件:只打印使用率超 80% 的分区
$ df -h | awk 'NR>1 && $5+0 > 80 {print $6" "$5}'
$5+0 是什么意思

$5"20%" 这样的字符串。+0 强制把它当数字算,awk 会自动把开头的数字部分取出来,"20%" 就变成 20

这是个常用小技巧,省掉一次 tr -d '%'

组装成一个小脚本

今天的成果
check-basic.sh
#!/bin/bash
# 简易检查:磁盘 + 服务

# ── 1. 磁盘使用率 ──
USE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')

if [ "$USE" -gt 80 ]; then
    echo "[告警] 根分区已用 ${USE}%"
else
    echo "[正常] 根分区已用 ${USE}%"
fi

# ── 2. 关键服务 ──
for svc in sshd crond nginx; do
    if systemctl is-active --quiet "$svc"; then
        echo "[正常] $svc"
    else
        echo "[告警] $svc 未运行"
    fi
done
跑起来
$ chmod +x check-basic.sh
$ ./check-basic.sh
[正常] 根分区已用 20%
[正常] sshd
[正常] crond
[正常] nginx
这就是明天那个脚本的骨架

明天会在它基础上加:内存检查、SSH 爆破统计、写日志、挂到 crontab,变成一个完整的、能拿去讲的东西。

今天的面试点

「写个脚本判断磁盘使用率超 80% 就告警」

能默写出这三行就够了:

USE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USE" -gt 80 ]; then
  echo "告警:${USE}%"

「取值 → 判断阈值 → 输出告警」这个结构,比背一堆语法有用得多。

「shell 里数字比较用什么?」

-gt-lt-eq 这些。不能用 >——那会被当成重定向,直接创建一个文件出来。」

这个坑答得出来,说明你真踩过。

今天的练习

敲完再走 · 约 18 分钟
  • 写一个 if 判断磁盘使用率的脚本,把阈值改成 10 让它触发告警分支,再改回 80
  • 故意踩坑:写 if [ "$USE" > 80 ],运行后 ls 看是不是多了个叫 80 的文件
  • 写个 for 循环检查 sshd crond nginx 三个服务
  • 练 awk 取值:df -h / | awk 'NR==2 {print $5}',试着改成取 $3$4 看是什么
  • free -m | awk 'NR==2 {printf "%.1f\n", $3/$2*100}',算出内存使用率
  • 把上面的 check-basic.sh 完整敲出来跑一遍(别复制粘贴,手敲)
  • bash -x ./check-basic.sh 看每一步的展开过程
明天是产出日

Day 28:写一个真正的巡检脚本,加上日志、挂到 crontab。

那是你简历上「写过自动化巡检脚本」这句话的底气来源。