欢迎光临
我们一直在努力

Shell编程之循环语句

在 Linux 运维和自动化脚本开发中,循环语句是实现批量处理和重复任务的核心工具。

本文将详细介绍 Shell 脚本中三种常用的循环语句:for、while 和 until,并通过丰富的实战案例,帮助你从理论走向实践,掌握高效编写 Shell 脚本的技巧。

一、for 循环:遍历列表的最佳选择

当你需要对一系列已知的对象(如用户名列表、IP 地址列表、文件名列表)执行相同操作时,for 循环是最直观、最简洁的选择。它的核心思想是 “遍历”,即依次取出列表中的每一个值,赋给变量,然后执行循环体内的命令。

1.1 for 循环的基本结构

for 循环的语法结构非常清晰:

for 变量名 in 取值列表

do

    命令序列

done

变量名:你自定义的一个变量,用于在每次循环中接收 “取值列表” 中的一个值。

取值列表:由空格分隔的多个值,也可以是命令的输出结果(如 $(cat file.txt))。

do…done:这对关键字包裹的是循环体,即每次循环要执行的命令。

for 循环的执行流程是:首先将列表中的第一个值赋给变量,执行 do…done 之间的命令;然后将列表中的下一个值赋给变量,再次执行命令…… 如此类推,直到列表中的所有值都被处理完毕,最后跳到 done 语句,结束循环。

1.2 实战案例:批量操作用户与主机

案例一:根据姓名列表批量添加 / 删除用户

假设人事部门给了你一个员工姓名列表 users.txt,你需要在 Linux 服务器中为这些员工批量创建用户账号,并设置统一的初始密码。

准备姓名列表文件:

# vim /root/users.txt

chenye

dengchao

zhangjie

编写批量添加用户的脚本 uaddfor.sh:

#!/bin/bash

# 从文件中读取用户名列表

ULIST=$(cat /root/users.txt)

# 遍历列表,逐个添加用户

for UNAME in $ULIST

do

    useradd $UNAME

    echo "123456" | passwd –stdin $UNAME &>/dev/null

done

执行脚本并验证:

chmod +x uaddfor.sh

./uaddfor.sh

tail -3 /etc/passwd # 查看是否成功创建用户

如果需要删除这些用户,只需将脚本中的 useradd 和 passwd 命令替换为 userdel -r 即可:

#!/bin/bash

ULIST=$(cat /root/users.txt)

for UNAME in $ULIST

do

    userdel -r $UNAME &>/dev/null

done

案例二:根据 IP 地址列表检查主机状态

另一个常见的场景是批量检查网络中多台主机的连通性。你可以将所有服务器的 IP 地址存入 ipadds.txt,然后用 for 循环遍历,使用 ping 命令检测每台主机是否在线。

准备 IP 地址列表文件:

# vim /root/ipadds.txt

172.16.16.1

172.16.16.22

172.16.16.220

编写主机检查脚本 chkhosts.sh:

#!/bin/bash

# 从文件中读取IP列表

HLIST=$(cat /root/ipadds.txt)

# 遍历列表,逐个ping测试

for IP in $HLIST

do

    # 发送3个ping包,间隔0.2秒,超时3秒

    ping -c 3 -i 0.2 -W 3 $IP &> /dev/null

    # 根据上一条命令的返回值($?)判断结果

    if [ $? -eq 0 ]

    then

        echo "Host $IP is up."

    else

        echo "Host $IP is down."

    fi

done

执行脚本:

chmod +x chkhosts.sh

./chkhosts.sh

脚本会清晰地输出每台主机的状态,例如:

plaintext

Host 172.16.16.1 is up.

Host 172.16.16.22 is up.

Host 172.16.16.220 is down.

二、while 循环:条件驱动的循环控制

for 循环擅长处理 “列表遍历”,而 while 循环则更适合 “条件驱动” 的场景。当你需要根据某个动态变化的条件来决定是否继续循环时,while 是更好的选择。

2.1 while 循环的基本结构

while 循环的语法结构如下:

while 条件测试操作

do

    命令序列

done

条件测试操作:这是 while 循环的核心。每次循环开始前,都会先判断这个条件的真假。

执行流程:如果条件为真(返回值为 0),则执行 do…done 之间的命令;执行完毕后,再次回到 while 判断条件。这个过程一直重复,直到条件测试的结果为假(返回值非 0),循环才会终止。

⚠️ 重要提示:使用 while 循环时,必须确保循环体内有语句能够改变测试条件,否则会造成 “死循环”,脚本将永远执行下去。

2.2 实战案例:批量创建规范用户与猜价格游戏

案例一:批量添加规律编号的用户

在一些培训或测试场景中,我们需要创建一批名称有规律的用户,例如 stu1、stu2、…、stu20。

编写批量创建脚本 uaddwhile.sh:

#!/bin/bash

# 定义用户名前缀

PREFIX="stu"

# 初始化计数器i

i=1

# 当i的值不大于20时,继续循环

while [ $i -le 20 ]

do

    # 创建用户stu+i

    useradd ${PREFIX}${i}

    # 设置初始密码

    echo "123456" | passwd –stdin ${PREFIX}$i &>/dev/null

    # 计数器i自增1,这是避免死循环的关键

    let i++

done

执行脚本并验证:

chmod +x uaddwhile.sh

./uaddwhile.sh

grep "stu" /etc/passwd | tail -3 # 查看最后三个用户

同样,删除这些用户也只需修改脚本中的命令:

#!/bin/bash

PREFIX="stu"

i=1

while [ $i -le 20 ]

do

    userdel -r ${PREFIX}$i

    let i++

done

案例二:猜价格游戏(完整实现)

这个案例是一个经典的交互式脚本,我们来完整实现它。脚本会先生成一个 0~999 的随机数作为 “商品价格”,然后提示用户输入猜测的数字,并给出 “太高了” 或 “太低了” 的提示,直到用户猜中为止。

#!/bin/bash

# 生成一个0-999的随机价格

PRICE=$(expr $RANDOM % 1000)

# 初始化猜测次数为0

TIMES=0

echo "商品实际价格范围为 0-999, 请猜猜看是多少?"

# 使用while true构造一个无限循环

while true

do

    # 读取用户输入的猜测值

    read -p "请输入你猜测的价格数目: " INT

    # 猜测次数加1

    let TIMES++

    # 判断用户输入与实际价格的关系

    if [ $INT -eq $PRICE ]

    then

        # 猜中了,输出恭喜信息和总次数,然后退出脚本

        echo "恭喜你答对了, 实际价格是 $PRICE"

        echo "你总共猜测了 $TIMES 次"

        exit 0

    elif [ $INT -gt $PRICE ]

    then

        # 猜高了,给出提示,继续循环

        echo "太高了!"

    else

        # 猜低了,给出提示,继续循环

        echo "太低了!"

    fi

done

执行效果如下:

plaintext

[root@localhost ~]# ./pricegame.sh

商品实际价格范围为 0-999, 请猜猜看是多少?

请输入你猜测的价格数目: 500

太高了!

请输入你猜测的价格数目: 250

太低了!

请输入你猜测的价格数目: 375

太高了!

请输入你猜测的价格数目: 280

太高了!

请输入你猜测的价格数目: 265

太高了!

请输入你猜测的价格数目: 253

恭喜你答对了, 实际价格是 253

你总共猜测了 6 次

三、until 循环:条件为假时执行

until 循环与 while 循环在结构上非常相似,但它们的逻辑恰好相反。

while:当条件为真时,执行循环。

until:当条件为假时,执行循环;直到条件变为真时,才停止循环。

3.1 until 循环的基本结构

until 条件测试操作

do

    命令序列

done

3.2 实战案例:计算累加和与在线消息推送

案例一:计算 1 到 50 的累加和

我们用 until 循环来实现从 1 累加到 50 的功能,直到 i 大于 50 时停止。

#!/bin/bash

i=0

s=0

# 当i不等于50时,继续循环

until [ $i -eq 50 ]

do

    let "i=i+1" # i自增1

    let "s=s+$i" # 将i累加到s中

done

echo 'sum(1..50)='$s # 输出结果

执行脚本,你会得到 sum(1..50)=1275 的正确结果。

案例二:为指定用户发送在线消息

假设公司有一台测试服务器,运维人员需要向已登录的开发人员发送紧急通知。如果用户不在线,就等待其登录后再发送。这个 “等待” 的场景非常适合用 until 或 while 来实现。

#!/bin/bash

# 检查参数数量是否足够

if [ $# -lt 2 ]; then

    echo "Usage: $0 <username1> <username2> … <message>"

    exit 1

fi

# 提取消息,消息是最后一个参数

message="${!#}"

# 遍历除最后一个参数外的所有用户名

for username in "${@:1:$#-1}"; do

    # 检查用户是否为系统内有效用户

    if ! grep -q "^${username}:" /etc/passwd; then

        echo "$username is not a valid user on this system."

        continue

    fi

    # 持续检查用户是否登录,直到其登录为止

    while ! who | grep -q "^${username}"; do

        echo "$username is not logged on. Waiting for the user to log in…"

        sleep 60 # 等待60秒后再次检查

    done

    # 用户已登录,发送消息

    echo "Sending message to $username…"

    write "$username" <<EOF

$message

EOF

    # 检查消息是否发送成功

    if [ $? -ne 0 ]; then

        echo "Failed to send message to $username."

    fi

done

这个脚本的使用方式是 ./until-user_online_to_write.sh 用户名 消息内容,例如:

./until-user_online_to_write.sh root "Are you ready ? root"

如果 root 用户在线,消息会立即发送;如果不在线,脚本会每 60 秒检查一次,直到 root 登录后发送消息。

四、总结

Shell 脚本中的三种循环语句各有千秋,选择合适的工具能让你的脚本更加高效和优雅:

for 循环:最适合处理预定义列表的遍历,如批量操作用户、批量处理文件等,逻辑清晰,代码简洁。

while 循环:擅长处理条件为真时重复执行的场景,如根据计数器循环、交互式程序等,是实现复杂逻辑的基础。

until 循环:与 while 相反,适合处理 “直到条件满足才停止” 的场景,如等待某个事件发生。

掌握这三种循环语句,并能在实际场景中灵活运用,是编写高效、可维护的 Shell 自动化脚本的必备技能。

赞(0)
未经允许不得转载:171主机测评 » Shell编程之循环语句
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址