Linux Shell 循环控制:从基础到实战,掌握重复执行的核心技巧
本文收录于《 Linux Shell 学习从入门到精通》
Linux Shell 循环控制:从基础到实战,掌握重复执行的核心技巧
在 Linux 系统管理和脚本开发中,重复执行某段代码是高频需求。Shell 提供的循环控制功能,能让脚本脱离“重复写代码”的低效模式,实现自动化批量操作。无论是处理批量文件、遍历目录内容,还是按条件重复任务,掌握循环控制都是提升 Shell 脚本能力的关键。
一、Shell 循环的核心类型:for、while、until
Shell 支持三种主流循环结构,每种结构适用场景不同,需根据“是否明确循环次数”“循环终止条件”来选择。
1. for 循环:明确次数的“遍历型”循环
for 循环适合已知循环次数或遍历固定列表的场景,比如处理指定文件、遍历数组元素等。
基础语法(列表遍历)
for 变量名 in 列表
do
循环体(需要重复执行的命令)
done
实战案例:批量重命名文件
将当前目录下所有 .txt 文件重命名为 old_原文件名.txt:
# 遍历当前目录下所有 .txt 文件
for file in *.txt
do
# 重命名文件,$file 代表当前遍历到的文件名
mv "$file" "old_$file"
done
进阶用法:数字范围遍历
无需手动写列表,用 {起始..结束} 或 seq 命令 生成数字序列:
# 方式1:用 { } 生成 1-5 的数字
for i in {1..5}
do
echo "当前数字:$i"
done
# 方式2:用 seq 生成 2-10 的偶数(步长为2)
for j in $(seq 2 2 10)
do
echo "当前偶数:$j"
done
2. while 循环:“条件满足就执行”的循环
while 循环适合未知循环次数、仅知道“循环终止条件”的场景,只要条件为“真”(返回值 0),就持续执行循环体。
基础语法
while 条件表达式
do
循环体
done
实战案例:读取文件内容
逐行读取 userlist.txt 文件(每行是一个用户名),并输出欢迎信息:
# 用 cat 读取文件内容,通过管道传给 while 循环
cat userlist.txt | while read username
do
echo "欢迎您,$username!"
done
# 更高效的写法(避免创建子进程)
while read username
do
echo "欢迎您,$username!"
done < userlist.txt
注意:避免“死循环”
若条件表达式始终为“真”,会导致循环无限执行,需确保循环体内有“让条件最终为假”的逻辑。例如:
# 正确示例:计数器达到 5 时终止
i=1
while [ $i -le 5 ]
do
echo "计数器:$i"
i=$((i+1)) # 计数器自增,最终让条件不满足
done
3. until 循环:“条件不满足就执行”的循环
until 循环与 while 逻辑相反:只要条件为“假”(返回值非 0),就执行循环体,直到条件为“真”时终止。适合“直到某个条件达成才停止”的场景。
基础语法
until 条件表达式
do
循环体
done
实战案例:等待服务启动
直到 8080 端口被占用(服务启动),才停止循环:
# 初始假设服务未启动(条件为假)
until nc -z localhost 8080
do
echo "等待服务启动..."
sleep 2 # 每隔 2 秒检查一次,避免频繁占用资源
done
echo "服务已启动!"
二、循环控制符:break、continue、exit
当循环执行到特定场景时,需要灵活调整流程(比如提前终止循环、跳过当前迭代),这就需要用到循环控制符。
1. break:终止当前循环
遇到 break 时,会直接跳出当前所在的循环,执行循环之后的代码。
案例:找到目标文件后停止遍历
在 /home 目录下查找 target.txt,找到后立即停止:
for file in $(find /home -name "target.txt")
do
echo "找到目标文件:$file"
break # 找到后跳出循环,不再继续查找
done
echo "查找结束"
2. continue:跳过当前迭代,进入下一次
遇到 continue 时,会跳过当前迭代剩余的代码,直接进入下一次循环判断。
案例:处理文件时跳过空文件
遍历 .txt 文件,若文件大小为 0,则跳过,不执行后续处理:
for file in *.txt
do
# 检查文件大小是否为 0
if [ -s "$file" -eq 0 ]; then
echo "跳过空文件:$file"
continue # 跳过当前文件,处理下一个
fi
# 非空文件的处理逻辑(例如统计行数)
line_count=$(wc -l < "$file")
echo "$file 的行数:$line_count"
done
3. exit:终止整个脚本
exit 会直接结束整个脚本的运行,无论当前处于哪个循环或代码块,常用于“遇到致命错误时停止脚本”。
案例:参数错误时终止脚本
脚本需要接收一个文件名作为参数,若未传入参数,则提示错误并终止:
# 检查参数数量是否为 1
if [ $# -ne 1 ]; then
echo "错误:请传入一个文件名作为参数!"
exit 1 # 退出脚本,返回状态码 1(表示错误)
fi
# 参数正确时的处理逻辑
file=$1
echo "正在处理文件:$file"
三、实战:综合循环案例
通过一个“批量备份日志文件”的案例,整合 for 循环、while 循环和控制符的用法:
需求:
- 备份
/var/log目录下 7 天前的.log文件 - 备份文件存到
/backup/logs目录,命名格式为“文件名_日期.tar.gz” - 若备份目录不存在,先创建;若备份失败,提示错误并继续下一个文件
#!/bin/bash
# 1. 定义变量
BACKUP_DIR="/backup/logs"
DATE=$(date +%Y%m%d) # 当前日期,格式:20240520
# 2. 检查备份目录,不存在则创建
if [ ! -d "$BACKUP_DIR" ]; then
mkdir -p "$BACKUP_DIR"
echo "创建备份目录:$BACKUP_DIR"
fi
# 3. 遍历 7 天前的 .log 文件(用 find 命令筛选)
for log_file in $(find /var/log -name "*.log" -mtime +7)
do
# 提取文件名(去掉路径)
filename=$(basename "$log_file")
# 定义备份文件名
backup_file="$BACKUP_DIR/${filename}_${DATE}.tar.gz"
# 4. 执行备份(打包压缩)
echo "正在备份:$log_file"
tar -zcf "$backup_file" "$log_file"
# 5. 检查备份是否成功($? 是上一条命令的返回状态码,0 为成功)
if [ $? -ne 0 ]; then
echo "错误:$log_file 备份失败!"
continue # 备份失败,跳过删除原文件,处理下一个
fi
# 6. 备份成功后,删除原文件(可选)
rm -f "$log_file"
echo "$log_file 备份完成,已删除原文件"
done
echo "所有符合条件的日志文件备份处理完毕"
总结
Shell 循环控制是脚本自动化的核心,关键在于“选对循环类型”和“用好控制符”:
- 明确循环次数或遍历列表 → 用 for 循环
- 条件满足时执行 → 用 while 循环
- 条件不满足时执行 → 用 until 循环
- 终止循环 → break;跳过当前迭代 → continue;终止脚本 → exit
若有转载,请标明出处:https://blog.youkuaiyun.com/CharlesYuangc/article/details/153472710
33万+

被折叠的 条评论
为什么被折叠?



