目录
一、for 循环语句
二、while 循环语句
三、until 循环语句
四、总结扩展
1. 循环对比
2. 调试技巧
3. 易混淆点解析
4. 进阶技巧
一、for 循环语句
1. 基础概念
含义:
用于 遍历一个已知的列表,逐个执行同一组命令
核心作用:
对一组固定或可枚举的数据(如文件列表、数字序列)进行重复操作。
结构:
for 变量 in 取值列表 do 命令组 done
2. 示例
根据姓名列表批量添加用户
1.准备测试文件(user_list.txt)
2.添加编辑脚本
#!/bin/bash # 定义用户列表文件路径
USER_LIST="/root/user_list.txt" # 检查文件是否存在
if [ ! -f "$USER_LIST" ]; then echo "错误:用户列表文件 $USER_LIST 不存在!" exit 1
fi # 使用 for 循环遍历文件中的用户名
for username in $(cat "$USER_LIST"); do # 跳过空行和注释行(以 # 开头) if [[ -z "$username" || "$username" == \#* ]]; then continue fi # 检查用户是否已存在 if id "$username" &> /dev/null; then echo " 用户 $username 已存在,跳过..." else # 创建用户并设置家目录 useradd -m "$username" # 设置初始密码(示例密码:123456) echo "123456" | passwd --stdin $username &>/dev/null ###stdin : 标准输入 ,默认用键盘输入echo "用户 $username 创建成功!" fi
done echo "所有用户处理完成!"
批量重启服务
#!/bin/bash
# 检查是否以 root 用户身份运行
if [ "$(id -u)" -ne 0 ]; then
echo "请以 root 用户身份运行此脚本。"
exit 1
fi
# 定义要重启的服务列表
services=("nginx" "mysql" "redis")
log_file="/var/log/service_restart.log"
# for 循环:批量重启服务
for service in "${services[@]}"; do
# 检查服务是否正在运行
if systemctl is-active --quiet $service; then
echo "正在重启 $service 服务..."systemctl restart $service
if [ $? -eq 0 ]; then
echo "$service 服务重启成功。"
else
echo "$service 服务重启失败。" | tee -a $log_filesystemctl status $service >> $log_file 2>&1
echo "---------------------" >> $log_file
fi
else
echo "$service 服务未运行,无需重启。"
fi
done
3. 注意事项
-
列表元素包含空格时需加引号:
for item in "file 1" "file 2"
-
使用
$@
遍历脚本参数:for param in "$@"
二、while 循环语句
1. 基础概念
含义:
当 条件测试结果为真(true)时,重复执行循环体,直到条件变为假(false)。
核心作用:
处理不确定循环次数的场景(如持续读取输入、等待某个状态变化)。
结构:
while [ 条件测试 ] do 命令组 done
2. 示例
批量添加规律编号的用户
#!/bin/bash PREFIX="stu"
#定义整数变量值为1
i=1#设置密码为123456的批量用户
while [ $i -le 20 ]
do useradd ${PREFIX}$iecho "123456" | passwd --stdin ${PREFIX}$i &> /dev/nulllet i++ done
echo "所有用户处理完成!"
持续监控磁盘使用率
#!/bin/bash
# 设定磁盘使用率阈值
threshold=80
# 日志文件路径
log_file="/var/log/disk_usage.log"# while 循环:持续监控磁盘使用率
while true; dousage=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')if [ $usage -gt $threshold ]; thentimestamp=$(date '+%Y-%m-%d %H:%M:%S')message="$timestamp - 磁盘使用率超过 $threshold%,当前使用率为 $usage%。"echo "$message" | tee -a $log_file # 可以添加发送邮件或者其他告警逻辑fisleep 3600 # 每小时检查一次
done
3. 注意事项
-
避免死循环:若条件永远为真(如
while true
),需手动退出(break) -
管道输入会创建子shell:
echo "文本" | while read
(子shell变量不传递到主进程)
三、until 循环语句
1. 基础概念
含义:
当 条件测试结果为假(false)时,重复执行循环体,直到条件变为真(true)。
核心作用:
与 while
逻辑相反,适用于需要“等待某个条件达成”的场景。
结构:
until [ 条件测试 ] # 条件为假时执行 do 命令组 done
2. 示例
指定用户发送在线消息
#!/bin/bash
# 检查参数数量是否足够
if [ $# -lt 2 ]; thenecho "Usage: $0 <username1> <username2> ... <message>"exit 0
fi# 提取消息,消息为最后一个参数
message="${!#}"# 遍历除最后一个参数外的所有用户名
for username in "${@:1:$#-1}"; do# 检查用户是否为系统内用户if ! grep -q "^$username:" /etc/passwd; thenecho "$(date +'%Y-%m-%d %H:%M:%S') - $username is not a valid user on this system."continuefi# 持续检查用户是否登录while ! who | grep -q "$username"; doecho "$(date +'%Y-%m-%d %H:%M:%S') - $username is not logged on. Waiting for the user to log in."sleep 60done# 检查用户是否允许接收消息if ! mesg -c | grep -q "is y"; thenecho "$(date +'%Y-%m-%d %H:%M:%S') - $username has disabled message reception."continuefi# 用户已登录,发送消息echo "$(date +'%Y-%m-%d %H:%M:%S') - Sending message to $username..."write "$username" <<EOF
$message
EOFif [ $? -ne 0 ]; thenecho "$(date +'%Y-%m-%d %H:%M:%S') - Failed to send message to $username."fi
done
持续尝试连接数据库,直至连接成功
#!/bin/bash
# 数据库连接信息
host="localhost"
port="3306"
user="root"
password="password"# until 循环:持续尝试连接数据库直到成功
until mysql -h $host -P $port -u $user -p$password -e "SELECT 1" &> /dev/null; doecho "无法连接到数据库,等待 10 秒后重试..."sleep 10
done
echo "成功连接到数据库。"
3. 特点
-
与
while
逻辑相反:条件为假时持续执行 -
适合「等待型」场景(如检测服务就绪)
四、总结扩展
1. 循环对比
循环类型 | 执行逻辑 | 典型场景 |
---|---|---|
for | 遍历列表中的每个元素 | 处理文件、已知范围的数值迭代 |
while | 条件为真时执行 | 读取输入流、条件动态变化的场景 |
until | 条件为假时执行 | 等待某条件满足(如服务启动) |
2. 调试技巧
#!/bin/bash -x # 开启调试模式查看循环执行细节 for file in * do : # 空语句用于占位调试 done
3. 易混淆点解析
-
while
vsuntil
:-
while
:条件为真时执行 → “只要...就继续” -
until
:条件为假时执行 → “直到...才停止”
-
-
for
vswhile
:-
for
关注 遍历数据,while
关注 动态条件。
-
4. 进阶技巧
-
嵌套循环:
for i in {1..3} do while [ $j -lt 2 ] do echo "$i-$j" ((j++)) done done
-
循环控制:
-
break
:立即退出循环。 -
continue
:跳过当前迭代,进入下一轮。
-
-
性能优化:
-
避免在循环内重复执行相同命令(如
ls
),优先缓存结果。 -
使用
&
后台执行耗时任务(需权衡并发控制) -
避免在循环内频繁调用
grep/awk
等外部命令 -
大数据处理优先使用管道和xargs
-
删除旧日志:
#!/bin/bash # 清理 30 天前的日志文件(处理特殊字符) LOG_DIR="/var/log/app" DAYS=30find "$LOG_DIR" -type f -name "*.log" -mtime +$DAYS -print0 | while IFS= read -r -d '' file; doecho "删除旧日志: $file"rm -f "$file" done
注释说明:
-
-mtime +30
:匹配修改时间超过 30 天的文件
-print0
+read -d ''
:安全处理含空格/换行符的文件名
-
避免频繁启动子进程:
# 低效写法:每次循环调用一次 `date` for i in {1..100}; do current_time=$(date) echo "$current_time" done # 高效写法:预先获取时间 current_time=$(date) for i in {1..100}; do echo "$current_time" done
总结速查表
场景 推荐循环 关键技巧 遍历文件列表 for
+ 引号包裹变量处理空格: find + while read -r
动态读取输入/条件变化 while
用 break
/continue
控制流程等待条件达成(如超时) until
结合 sleep
避免 CPU 占用过高高性能批量处理 xargs
/parallel
并行加速,减少子进程开销 无限循环 while true
确保有退出条件(如 Ctrl+C
捕获信号)