一、Shell 里的循环主要分三种¶
原笔记把循环分为:
for:最常用,适合遍历清单while:更灵活,适合条件判断、死循环、读文件until:极少用,但需要知道
这三者的区别不在语法本身,而在于“你要处理的是列表、条件还是持续等待”。
二、for 循环最适合做批量遍历¶
2.1 最常用的 for 格式¶
for n in {1..10}
do
echo $n
done
候选清单可以来自很多地方:
- 手写列表
- 花括号扩展,例如
{1..10}、{a..e} seq- 命令结果
2.2 C 风格 for¶
for((i=1;i<=10;i++))
do
echo $i
done
这种写法在数组遍历时尤其常见。
三、案例:批量创建随机文件¶
原笔记给出的经典题目,是在 /oldboy 目录下批量创建 10 个随机文件名的 HTML 文件:
#!/bin/bash
dir=/oldboy/
[ -d $dir ] || mkdir $dir
for n in {1..10}
do
filename_suiji=$(mkpasswd -l 10 -s 0)
filename_full=${filename_suiji}_oldboy.html
cd $dir
touch $filename_full
done
这个案例很好地体现了 for 的价值:同一组动作,用循环一次性处理多个对象。
四、while 循环更适合做条件处理¶
4.1 基础格式¶
while 条件
do
命令
done
while 的关键是:只要条件成立,就持续执行。
4.2 输出 1 到 10¶
#!/bin/bash
i=1
while [ $i -le 10 ]
do
echo $i
let i++
done
4.3 计算 1 到 100 的和¶
#!/bin/bash
i=1
sum=0
while [ $i -le 100 ]
do
let sum=sum+i
let i++
done
echo $sum
这个案例也说明:循环和整数运算通常是一起出现的。
五、死循环最适合做持续交互¶
原笔记用“猜数字游戏”说明了死循环的典型应用场景:持续读入、持续判断,直到满足退出条件。
#!/bin/bash
guess_num=$((RANDOM % 100 + 1))
i=0
check_percent() {
if [ $i -le 3 ]; then
echo "您超越了99.99%的人"
elif [ $i -ge 4 -a $i -le 6 ]; then
echo "您超越了80%的人"
else
echo "您超越了70%的人"
fi
}
while true; do
read -p "请输入你猜测数字: " num
if ! [[ "$num" =~ ^[0-9]+$ ]]; then
echo "请输入数字"
continue
fi
let i++
if [ $num -eq $guess_num ]; then
echo "恭喜您猜对了"
check_percent
exit 0
fi
if [ $num -gt $guess_num ]; then
echo "数字过大,请换一个更小的数字"
else
echo "数字过小,请换一个更大的数字"
fi
done
这个脚本把循环、正则判断、函数、分支判断都串起来了,是一份很好的综合练习。
六、while read 是读文件的高频写法¶
原笔记对读文件场景给了 3 种方式,但最推荐的是在 done 后面直接接输入重定向:
while read line
do
echo $line
done < file.txt
原因是这种写法不会额外开子 Shell,循环里修改的变量在后面还能继续使用。
6.1 案例:统计文件行数¶
#!/bin/bash
file=num.txt
i=0
while read line
do
let i++
done < $file
echo "$file 文件一共有 $i 行"
这已经是处理配置文件、主机列表、日志结果文件时的标准动作。
七、案例:日志分析后做防 DOS 处理¶
原笔记里最像真实生产脚本的循环案例,是先统计访问日志,再逐行处理异常 IP:
#!/bin/bash
access_log="/var/log/nginx/access.log-20240104"
result_file="/server/files/result.txt"
awk '{print $1}' "$access_log" | sort | uniq -c | sort -rn | head -5 > "$result_file"
while read line
do
ip_cnt=$(echo "$line" | awk '{print $1}')
ip_addr=$(echo "$line" | awk '{print $2}')
if [ "$ip_cnt" -ge 200 -a $(iptables -nL | grep -wc "${ip_addr}") -eq 0 ]
then
iptables -t filter -I INPUT -s "$ip_addr" -j DROP
fi
done < "$result_file"
这个案例体现了 Shell 自动化的典型组合拳:
- 三剑客先做统计
while read逐行读取结果if判断是否满足封禁条件iptables执行动作
八、until 和循环控制语句也要会用¶
原笔记虽然强调 until 很少用,但还是给出了基本格式:
until 条件
do
命令
done
它和 while 的思路相反:只要条件不满足就继续执行。
另外 4 个循环相关的控制语句也必须认识:
exit:终止脚本return:终止函数并返回状态码break:退出循环continue:跳过本次循环
例如:
for n in {1..10}
do
[ $n -eq 5 ] && break
echo $n
done
for n in {1..10}
do
[ $n -eq 5 ] && continue
echo $n
done
九、循环这章真正的重点¶
把原笔记所有案例看完后,可以把循环理解成下面 3 种能力:
for:批量遍历一组对象while:持续处理条件或输入while read:批量读取文件并执行动作
运维自动化里,真正有价值的不是“会写循环语法”,而是能把循环和判断、三剑客、系统命令组合起来,批量完成原本需要手工重复的操作。