2. Shell脚本基础回顾:变量、条件判断、循环
写巡检脚本,说白了就是跟文件、路径、日志打交道。Shell脚本就像你的"自动化双手",而变量、条件判断、循环就是这双手的核心关节。我个人习惯把这三样东西称为"脚本三要素"——你想想看,任何复杂的巡检任务,拆开来看无非就是:存数据(变量)、做判断(条件)、重复干(循环)。这一章,我把这三个基本功掰开揉碎讲清楚,顺便分享一些我当年踩过的坑。
2.1 变量:脚本的"储物格"
变量就是给数据起个名字。在Shell里,变量不需要提前声明,直接用就行。比如你想存日志路径:
log_path="/var/log/audit"
retention_days=30
这里有个大坑——变量赋值等号两边不能有空格。我在项目中遇到过新人同事(包括当年的我)写成了 log_path = "/var/log/audit",结果脚本直接报错。为什么会这样?因为Shell把 log_path 当命令,= 和 "/var/log/audit" 当参数去了。记住:赋值就是 变量=值,中间一个空格都不能多。
引用变量时加 $ 符号:
echo "日志路径: $log_path"
echo "保留天数: ${retention_days}天"
我个人习惯给变量名加花括号,比如 ${log_path},这样在拼接字符串时更安全,也更容易看清楚变量边界。尤其是后面紧跟字母或数字时,花括号能避免歧义。
常用变量类型快速参考:
| 类型 | 示例 | 说明 |
|---|---|---|
| 普通变量 | log_dir="/var/log" |
存路径、文件名、时间等 |
| 环境变量 | $HOME、$USER、$PATH |
系统预置,可直接使用 |
| 特殊变量 | $?、$0、$# |
上条命令退出码、脚本名、参数个数 |
| 局部变量 | local count=0 |
函数内使用,避免污染全局 |
log_file_path、max_file_size。别用驼峰,也别用短横线(Shell会把短横线当成减号)。
2.2 条件判断:让脚本会"思考"
条件判断让脚本有了"脑子"。最基本的结构是 if-then-else,格式长这样:
if [ 条件 ]; then
# 条件成立时执行
else
# 条件不成立时执行
fi
条件判断的核心是 test 命令,[ ] 就是它的简写。我用一张表把这几种判断类型列清楚:
| 类型 | 表达式 | 说明 |
|---|---|---|
| 数值比较 | [ $a -eq $b ] |
等于 |
[ $a -ne $b ] |
不等于 | |
[ $a -gt $b ] |
大于(还有 -lt -ge -le) | |
| 字符串比较 | [ "$str" = "value" ] |
等于(注意双引号不能省) |
[ -z "$str" ] |
字符串为空 | |
| 文件判断 | [ -f "$file" ] |
文件存在且是普通文件 |
[ -d "$dir" ] |
目录存在 | |
[ -s "$file" ] |
文件存在且非空 |
我最常用的组合:检查日志文件是否存在,且大小超过阈值。比如这样:
log_file="/var/log/audit/audit.log"
if [ -f "$log_file" ] && [ $(stat -c%s "$log_file") -gt 10485760 ]; then
echo "日志文件超过10MB,需要处理"
fi
audit 2024.log),没加引号导致判断失败,排查了大半天。加引号不是习惯问题,是保命操作。
如果条件分支超过两个,可以用 elif 串联:
if [ "$status" -eq 0 ]; then
echo "正常"
elif [ "$status" -eq 1 ]; then
echo "警告"
else
echo "异常"
fi
2.3 循环:重复任务的"加速器"
巡检脚本里最常用的就是 for 循环和 while 循环。说白了,循环让你不用一遍遍地写重复代码。
for 循环适合遍历列表:
for host in server1 server2 server3; do
echo "正在检查: $host"
ssh "$host" "tail -100 /var/log/audit/audit.log"
done
while 循环适合逐行读取文件:
while read -r line; do
echo "处理日志行: $line"
done < /var/log/audit/audit.log
再补充一个实用技巧:用 {..} 生成数字序列来循环:
for i in {1..5}; do
echo "第${i}次巡检"
done
sleep 控制节奏,尤其当你要遍历大量文件或远程主机时。不加sleep,系统负载可能瞬间飙升,生产环境里这是大忌。
还有一种 until 循环,和 while 正好相反——条件为真时停止。用的场景不多,但某些等待场景下很顺手:
until [ -f "/tmp/flag" ]; do
echo "等待标志文件生成..."
sleep 5
done
echo "标志文件已就绪"
2.4 综合示例:巡检脚本片段
把变量、条件判断、循环组合起来,就是一个完整的巡检脚本雏形。下面这个例子,做了三件事:定义变量、遍历日志、检查大小:
#!/bin/bash
# 审计日志巡检脚本 - 基础版
log_dir="/var/log/audit"
threshold=1000000
echo "开始巡检: $(date)"
for log_file in "$log_dir"/*.log; do
if [ -f "$log_file" ]; then
file_size=$(stat -c%s "$log_file")
if [ "$file_size" -gt "$threshold" ]; then
echo "警告: $log_file 大小 ${file_size} 超过阈值"
fi
fi
done
echo "巡检结束: $(date)"
log_dir、threshold)、条件判断做大小检查(-f、-gt)、循环遍历文件(for)。实际生产环境的巡检脚本,无非是在这个骨架上增加告警、记录、轮转等细节。记住这个骨架,后面的章节都是往上添砖加瓦。