for 循环语句的应用实践
在Shell脚本编程中,for循环与while循环功能相似,但其主要适用于已知执行次数的场景,而不常用于无限循环或守护进程类任务。常见的for循环有两种语法结构,本文将围绕这两种形式展开详细说明。
for 循环的语法结构 —— 变量取值型
第一种典型的for循环语法如下所示:
for 变量名 in 变量取值列表
do
指令...
done
其中,“in 变量取值列表”部分可以被省略。若省略该部分内容,则等价于使用特定默认方式遍历参数列表。即:
in "$@"
也就是说,不写“in 变量取值列表”时,系统会自动读取脚本传入的参数作为变量值来源。因此,以下两种写法是等效的:
for i
等同于:
for i in "$@"
for 循环的执行流程解析
该类型for循环的运行机制如下:
- 在
for关键字后定义一个“变量名”,此变量将依次从in后面的列表中获取值(以空格为分隔符); - 每次仅取一个值赋给变量,随后进入循环体(位于
do和done之间的代码段),执行其中的所有命令; - 当程序执行到
done时,本次循环结束; - 接着,变量继续取列表中的下一个值,重复上述过程;
- 直至遍历完整个变量列表中的所有值,整个循环终止。
基础实践案例:用户管理脚本
下面通过一个实际的Shell脚本示例,展示如何结合for循环思想实现对自定义用户列表的增、删、查操作。
#!/bin/bash
# root 身份运行
((UID!=0)) && echo 'pls run as root.' && exit
# 打印结果状态:成功或失败
function print ()
{
case $1 in
SUCCESS)
echo -e '\033[1;32mPASS\033[0;39m'
;;
FAIL)
echo -e '\033[1;31mFAIL\033[0;39m'
;;
*)
echo "Usage: print SUCCESS|FAIL"
;;
esac
}
# 显示脚本使用方法
function usage ()
{
echo 'Usage: user-mgr [ [ -a|--add ] | [ -d|--del ] | [ -s|--search ] ] username'
exit
}
# 检查参数数量是否正确
[ $# -ne 2 ] && usage
# 创建用户信息存储文件
user_file=/etc/users
[ -f ${user_file} ] || echo > ${user_file}
username="$2"
# 查询用户是否存在
function user_search ()
{
egrep -q "^username: $username$" ${user_file}
search_result=$?
if ((search_result==0)); then
echo "$username is exist."
else
echo "$username is not exist."
fi
}
# 添加用户
function user_add ()
{
if user_search | grep -q 'not'; then
sed -i "1iusername: $username" ${user_file} &> /dev/null
add_result=$?
echo -n "Add user ... "
if ((add_result==0)); then
print SUCCESS
else
print FAIL
echo "$(date) Add user ... $(print FAIL)" >> /tmp/user-mgr.log
fi
else
echo "$username is exist."
fi
}
# 删除用户
function user_del ()
{
if user_search | grep -q 'not'; then
echo "$username is not exist."
else
sed -ri "/^username: $username$/d" ${user_file} &>/dev/null
del_result=$?
echo -n "Del user ... "
if ((del_result==0)); then
print SUCCESS
else
print FAIL
echo "$(date) Del user ... $(print FAIL)" >> /tmp/user-mgr.log
fi
fi
}
# 主逻辑分支控制
case $1 in
-a|--add)
user_add
;;
-d|--del)
user_del
;;
-s|--search)
user_search
;;
*)
usage
;;
esac
该脚本实现了基于命令行参数的操作选择,能够以-a添加用户、-d删除用户、-s查询用户状态,并将操作结果输出至终端,同时记录失败日志到指定文件中。虽然本例未直接使用for循环,但其结构清晰,便于后续扩展为批量处理多个用户名的循环操作。
努力实现一个亿的小目标
#!/bin/bash
target=100000000
money=1
until ((money >= target)); do
((money += 10000000))
echo -n "正在努力奋斗中 .... 当前金额: "
sleep 0.5
echo $money
done
money=1
while ((money < target)); do
((money += 10000000))
echo -n "正在努力奋斗中 .... 当前金额: "
sleep 0.5
echo $money
done
该脚本通过循环逐步增加变量值,模拟积累财富的过程,直到达到一亿元的目标。使用了 while 和 until 两种循环结构来实现相同逻辑,展示控制流程的多样性。
- 一个公鸡5钱
- 一个母鸡3钱
- 三只鸡3钱
问100钱能买公、母、雏各多少只
监控 sshd 服务运行状态
以下脚本持续检测 sshd 服务是否处于激活状态,若发现未运行,则自动启动并记录日志:
#!/bin/bash
while true; do
systemctl is-active sshd &> /dev/null
rc=$?
if ((rc != 0)); then
echo "$(date) Sshd 服务未运行。" >> /tmp/monitor_sshd.log
systemctl start sshd && echo "$(date) 成功启动 sshd 服务。" >> /tmp/monitor_sshd.log
fi
sleep 3
done
此脚本利用无限循环定期检查服务状态,确保远程连接能力始终可用,适用于服务器运维自动化场景。
CPU 负载压力测试脚本设计
根据需求,需编写两个脚本以进行 CPU 压力测试:
1. cpu_load:用于占用单个 CPU 核心的全部计算资源。
2. all_load:动态启动多个 cpu_load 实例,直至占满系统所有 CPU 核心。
脚本内容如下:
cpu_load 脚本:
#!/bin/bash
while true; do
((1 + 1))
done
all_load 脚本:
#!/bin/bash
total_cpu_count=$(lscpu | awk 'NR==4 { print $2 }')
while true; do
current_cpu_count=$(ps axu | grep cpu_load | grep -v grep | wc -l)
if ((current_cpu_count < total_cpu_count)); then
bash /root/bin/cpu_load &
else
sleep 3
fi
done
all_load 脚本首先获取系统 CPU 总核数,然后不断检查当前运行的 cpu_load 进程数量,若不足则启动新进程,从而实现全核负载。
自动配置 SSH 免密登录
以下脚本可实现自动配置本地主机对指定远程主机的 SSH 密钥认证登录:
#!/bin/bash
# 禁用主机密钥检查提示
grep -q '^StrictHostKeyChecking no' /etc/ssh/ssh_config || \
echo 'StrictHostKeyChecking no' >> /etc/ssh/ssh_config
# 若无 RSA 密钥对则生成
[ -f ~/.ssh/id_rsa ] || ssh-keygen -f ~/.ssh/id_rsa -N ''
# 向目标主机分发公钥
for host in 10.1.8.{10,11}; do
sshpass -p 123 ssh-copy-id root@$host &>/dev/null && \
echo "公钥推送成功。"
ssh root@$host hostname &>/dev/null && \
echo "密钥登录验证成功。"
done
该脚本简化了多机环境下的 SSH 免密配置流程,适合批量部署场景。
逻辑推理题:三对情侣的婚礼配对
题目描述:
三位新郎分别为 A、B、C,三位新娘分别为 X、Y、Z。三人发言如下:
- A 称他将与 X 结婚;
- X 称她的未婚夫是 C;
- C 称他将与 Z 结婚。
但事后得知,以上三句话均为假话。请推断出真实的婚配关系。
解题思路:
由于三人所说皆为谎言,因此可根据其陈述反向推理:
1. A 说“我与 X 结婚” → 实际上 A 不会与 X 结婚;
2. X 说“我的未婚夫是 C” → 实际上 X 的未婚夫不是 C;
3. C 说“我将与 Z 结婚” → 实际上 C 不会与 Z 结婚。
由此得出排除条件:
- A ≠ X
- X 的伴侣 ≠ C → 即 C ≠ X
- C ≠ Z
结合以上信息:
- 新郎可选新娘为 {X, Y, Z}
- 每人仅能匹配一次
从 C 的限制入手:
- C ≠ Z,且 C ≠ X → 故 C 只能与 Y 结婚。
剩余新娘为 X 和 Z,剩余新郎为 A 和 B。
A 不能与 X 结婚 → 故 A 必须与 Z 结婚。
最后 B 与 X 结婚。
最终婚配结果为:
- A 与 Z 结婚
- B 与 X 结婚
- C 与 Y 结婚
一个人无法同时与多个人结为夫妻。
in "$@"
编写一个猜数字游戏的实现思路
程序需要在1到100之间生成一个随机数,供用户猜测。用户每次输入一个数字后,系统将判断该数字与目标值的关系:
- 若用户猜测的数值偏大,则提示“猜大了”;
- 若猜测的数值偏小,则提示“猜小了”;
- 若猜测正确,则显示笑脸符号以示祝贺。
用户最多拥有五次猜测机会,超过次数则游戏自动结束。
实现方法说明
利用 Bash 中的 $RANDOM 变量可生成一个介于 0 到 32767 之间的随机整数。通过取模运算将其范围调整为 1 至 100:
num_result=$[ RANDOM % 100 + 1 ]
随后将结果保存至临时文件以便调试或验证:
echo $num_result > /tmp/num
接着使用循环控制用户最多输入五次:
for ((i=1;i<=5;i++))
每次读取用户的输入:
read -p "请输入1个1~100之间的数字:" num_guess
然后进行比较判断:
if ((num_guess>num_result));then
echo " 第 $i 次猜测:猜大了。"
elif ((num_guess<num_result));then
echo " 第 $i 次猜测:猜小了。"
else
echo " 第 $i 次猜测:猜对了。"
exit
fi
完整脚本代码如下:
#!/bin/bash
num_result=$[ RANDOM % 100 + 1 ]
echo $num_result > /tmp/num
echo "你有5次猜测机会,谨慎猜测。"
for ((i=1;i<=5;i++))
do
read -p "请输入1个1~100之间的数字:" num_guess
if ((num_guess>num_result));then
echo " 第 $i 次猜测:猜大了。"
elif ((num_guess<num_result));then
echo " 第 $i 次猜测:猜小了。"
else
echo " 第 $i 次猜测:猜对了。"
exit
fi
done
九九乘法表的 Bash 实现
通过嵌套循环实现标准的九九乘法表输出:
- 外层循环遍历行号(即被乘数,从1到9);
- 内层循环遍历当前行中的列(即乘数,从1到当前行号);
- 每轮计算两数乘积,并格式化输出。
采用 printf 进行对齐输出,确保显示整齐美观:
#!/bin/bash
# 遍历行(被乘数 num1:1-9)
for num1 in {1..9};
do
# 遍历列(乘数 num2:1-当前行号)
for ((num2=1; num2<=num1; num2++));
do
# 计算乘积(使用 $((...)) 替代旧式 $[...],提升兼容性)
product=$((num2 * num1))
# 格式化输出:每个表达式占8个字符宽度,左对齐
printf "%d*%d=%-2d\t" "$num2" "$num1" "$product"
done
# 每行结束后换行
echo
done
关于朋友配对的脚本逻辑分析
以下脚本用于解决一个逻辑匹配问题:A、B、C三人分别与三位朋友X、Y、Z中的一人配对,满足特定条件。
定义函数 print_friend,根据传入参数返回对应的朋友名称:
print_friend ()
{
friend=$1
case $friend in
1)
echo X
;;
2)
echo Y
;;
3)
echo Z
;;
esac
}
使用三重循环枚举所有可能的组合(a, b, c),并施加约束条件:
- a 不等于 1(A 不跟 X);
- c 不等于 1(C 不跟 X);
- c 不等于 3(C 不跟 Z);
- a、b、c 互不相等(每人只能匹配一人,无重复)。
符合条件的结果将被打印输出:
for ((a=1;a<=3;a++))
do
for ((b=1;b<=3;b++))
do
for ((c=1;c<=3;c++))
do
if ((a!=1 && c!=1 && c!=3 && a!=b && b!=c && a!=c));then
echo "A 跟 $(print_friend $a)"
echo "B 跟 $(print_friend $b)"
echo "C 跟 $(print_friend $c)"
fi
done
done
done
for i

雷达卡


京公网安备 11010802022788号







