目录
一:for循环语句
在实际工作中,经常会遇到某项任务需要多次执行的情况,而每次执行时仅仅是处理的对象不一样,其他命令相同。例如,根据通讯录中的姓名列表创建系统账号,根据服务器清单检査各主机的存活状态,根据 IP 地址黑名单设置拒绝访问的防火墙策略等。
当面对各种列表重复任务时,使用简单的 if 语句已经难以满足要求,而顺序编写全部代码更是显得异常烦琐、困难重重。本节将要学习的 for 循环语句,可以很好地解决类似问题。
1:for语句的结构
使用 for 循环语句时,需要指定一个变量及可能的取值列表,针对每个不同的取值重复执行相同的命令序列,直到变量值用完退出循环。在这里,“取值列表”称为for语句的执行条件,其中包括多个属性相同的对象,需要预先指定(如通讯录、IP 黑名单)。
for 循环语句的语法结构如下所示。
for 变量名 in 取值列表
do
命令序列
done
1. 标准 for 循环(计数循环)
适用于大多数类 C 语言(C/C++/Java/JavaScript 等)。
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
初始化; 条件; 增量 | for (init; condition; update) { ... } | for (int i = 0; i < 10; i++) { ... } | 最经典的 for 循环,适用于精确控制循环次数 |
2. 范围 for 循环(foreach 循环)
适用于遍历数组、集合或范围(Python、Kotlin、C++11 等)。
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
遍历元素 | for (var item : collection) { ... } | for (int num : numbers) { ... } | 适用于遍历数组、列表等 |
Python 风格 | for item in iterable: | for x in range(10): | Python、Ruby 等语言使用 |
带索引遍历 | for index, item in enumerate(iterable): | for i, val in enumerate(lst): | Python 支持同时获取索引和值 |
3. 无限 for 循环
适用于需要无限循环的场景(如事件循环)。
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
无条件循环 | for (;;) { ... } | for (;;) { ... } | C/C++/Java 的无限循环写法 |
Go 风格 | for { ... } | for { ... } | Go 语言省略条件,直接无限循环 |
4. 字典/Map 遍历
适用于遍历键值对(Python、JavaScript、Go 等)。
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
遍历键 | for key in dict: | for key in my_dict: | Python 默认遍历键 |
遍历键值对 | for key, value in dict.items(): | for k, v in my_dict.items(): | Python 的字典遍历 |
JS for...in | for (let key in obj) { ... } | for (let k in obj) { ... } | JS 遍历对象属性 |
JS for...of | for (let value of iterable) { ... } | for (let x of arr) { ... } |
5. 特殊 for 循环(不同语言特性)
某些语言有独特的 for 循环变体。
语言 | 结构 | 示例 | 说明 |
---|---|---|---|
Go | for init; condition; update { ... } | for i := 0; i < 10; i++ { ... } | 类似 C,但无括号 |
Rust | for item in iterable { ... } | for x in 0..10 { ... } | 类似 Python |
Shell | for var in list; do ... done | for i in {1..5}; do ... done |
总结对比
循环类型 | 适用场景 | 典型语言 |
---|---|---|
标准 for | 精确控制循环次数 | C, C++, Java, JavaScript |
foreach | 遍历集合/数组 | Python, Kotlin, C# |
无限 for | 事件循环、服务器监听 | C (for(;;) ), Go (for {} ) |
字典遍历 | 处理键值对 | Python (dict.items() ), JS (for...in ) |
范围循环 | 数字范围遍历 | Python (range ), Rust (0..10 ) |
2:for语言应用示例
为了进一步理解 for 语句的结构和流程,掌握 for 语句在脚本中的实际使用,下面依次介绍两个脚本示例。
(1)根据姓名列表批量添加用户
根据人事部门给出的员工姓名的拼音列表,在Linux服务器中添加相应的用户账号,初始密码均设置为“123456”。其中,员工姓名列表中的账号数量并不固定,而且除了要求账号名称是拼音之外,并无其他特殊规律。
针对上述要求,可先指定员工列表文件 users.txt,然后编写一个名为 uaddfor.sh 的Shell 脚本,从 users.txt 文件中读取各用户名称,重复执行添加用户、设置初始密码的相关操作。
若要删除 uaddfor.sh 脚本所添加的用户,只需参考上述脚本代码,将 for 循环体中添加用户的命令序列改为删除用户的操作即可。例如,建立一个名为udelfor.sh 的脚本如下所示。
(2) 根据IP地址列表检查主机状态
根据包含公司各服务器 IP 地址的列表文件,检査其中各主机的 ping 连通性,输出各主机是否启动、关闭。其中,服务器的数量并不固定,各服务器的IP地址之间也无特殊规律。
针对此案例要求,可先指定 IP 地址列表文件 ipadds.txt,然后编写一个名为 chkhosts.sh 的Shell脚本,从 ipadds.txt 文件中读取各服务器的 IP 地址,重复执行 ping 连通性测试,并根据测试结果输出相应的提示信息。
[root@localhost ~# chmod +x chkhosts.sh
[root@localhost ~]#./chkhosts.sh
Host 172.16.16.1 is up.
Host 172.16.16.22 is up.
Host 172.16.16.220 is down.
上述脚本代码中,do…done 循环体内嵌套使用了 if 条件选择语句,用来针对不同 IP 地址的测试结果进行判断,并输出相应的提示信息。嵌套可以理解为镶嵌、套用,就是在已有的语句、函数中在多加一个或多个语句、函数等。实际上,if 语句、for 语句及其他各种 shell脚本语句都是可以嵌套使用的,后续课程中将不再重复说明。
二:使用while循环语句
for 循环语句非常适用于列表对象无规律,且列表来源已固定(如某个列表文件)的场合。而对于要求控制循环次数、操作对象按数字顺序编号、按特定条件执行重复操作等情况,则更适合使用另外一种循环-while 语句。
1:while语句的结构
使用 while 循环语句时,可以根据特定的条件反复执行一个命令序列,直到该条件不再满足时为止。在脚本应用中,应该避免出现死循环的情况,否则后边的命令操作将无法执行。因此,循环体内的命令序列中应包括修改测试条件的语句,以便在适当的时候使测试条件不再成立,从而结束循环。
while 循环语句的语法结构如下所示。
while 条件测试操作
do
命令序列
done
1. 标准 while 循环(先判断后执行)
适用语言:C/C++/Java/JavaScript/Python/Go/PHP 等
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
while (条件) { ... } | while (condition) { ... } | while (x < 10) { ... } | 先检查条件,再执行循环体 |
Python 风格 | while condition: | while x < 10: | Python 使用 : 和缩进 |
Go 风格 | for condition { ... } | for x < 10 { ... } | Go 用 for 代替 while |
2. do-while 循环(先执行后判断)
适用语言:C/C++/Java/JavaScript/PHP 等(Python 不支持)
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
do { ... } while (条件); | do { ... } while (condition); | do { ... } while (x < 10); | 至少执行一次,再检查条件 |
Java/JS 风格 | do { ... } while (cond); | do { ... } while (i < 5); | 末尾必须有分号 ; |
3. 无限 while 循环
适用于需要 持续运行 的场景(如服务器监听、事件循环)。
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
while (true) { ... } | while (true) { ... } | while (true) { ... } | 经典无限循环 |
Python 风格 | while True: | while True: | Python 用 True 代替 true |
Go 风格 | for { ... } | for { ... } | Go 用 for 代替 while |
4. 特殊 while 循环(不同语言特性)
某些语言有独特的 while
循环变体。
语言 | 结构 | 示例 | 说明 |
---|---|---|---|
Shell (Bash) | while [ condition ]; do ... done | while [ $x -lt 10 ]; do ... done | Bash 使用 [...] 或 ((...)) 判断条件 |
Rust | while condition { ... } | while x < 10 { ... } | 类似 C,但无括号 |
Kotlin | while (condition) { ... } | while (x < 10) { ... } | 与 Java 相同 |
总结对比
循环类型 | 适用场景 | 典型语言 |
---|---|---|
标准 while | 先判断后执行 | C/C++/Java/JS/Python |
do-while | 先执行后判断(至少执行一次) | C/C++/Java/JS |
无限 while | 持续运行(如服务器监听) | while (true) / for {} (Go) |
Shell while | Bash 脚本循环 | while [ cond ]; do ... done |
2:while 语句应用示例
为了进一步理解 while 语句的结构和流程,掌握 while 语句在脚本中的实际使用,下面依次介绍一个脚本示例。
(1)猜价游戏
中央电视台著名的“时尚购物街”节目中,有一个猜价格的互动环节,要求参与者在最短的时间内猜出展示商品的实际价格,当所猜的价格高出或低于实际价格时,主持人会给出相应的提示。下面以此环节为原型,编写一个猜价格的 Shell 脚本。
案例要求如下:由脚本预先生成一个随机的价格数目(0~999)作为实际价格,判断用户猜测的价格是否高出或低于实际价格,给出相应提示后再次要求用户猜测;一直到用户猜中实际价格为止,输出用户共猜测的次数、实际价格。
针对上述要求,主要设计思路如下:通过环境变量RANDOM 可获得一个小于 216的随机整数,计算其与 1000 的余数即可获得 0~999 的随机价格;反复猜测操作可以通过以 true 作为测试条件的while 循环实现,当用户猜中实际价格时终止循环;判断猜测价格与实际价格的过程采用 if 语句实现,嵌套在 while 循环体内;使用变量来记录猜测次数。
三:until 循环语句
1:until 语句的结构
until 循环与 while 循环类似,while 循环能实现的脚本 until同样也可以实现,但区别是while循环在条件为真是继续执行循环,而until则是在条件为假时执行循环。
until 循环语句的语法结构如下所示。
until 条件测试操作
do
命令序列
done
1. 标准 until 循环(条件为假时执行)
适用语言:Shell/Bash、Ruby、Perl 等
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
until [条件] (Bash) | until [ condition ]; do ... done | until [ $x -ge 10 ]; do ... done | Bash 风格,[ ] 是条件测试 |
until 条件 (Ruby) | until condition do ... end | until x >= 10 do ... end | Ruby 风格,do...end 可换行 |
until (条件) (Perl) | until (condition) { ... } | until ($x >= 10) { ... } | Perl 风格,类似 while 但逻辑相反 |
2. 模拟 until 循环(其他语言)
大多数语言(如 C/C++/Java/Python)没有 until
,但可用 while
实现相同逻辑:
语言 | 实现方式 | 示例 | 说明 |
---|---|---|---|
C/C++/Java/JS | while (!condition) { ... } | while (x < 10) { ... } | 用 while 加逻辑取反 |
Python | while not condition: | while not x >= 10: | Python 用 not 反转条件 |
Go | for !condition { ... } | for !(x >= 10) { ... } | Go 用 for 代替 while |
3. until 无限循环
某些语言支持 until
无限循环(需手动 break
):
结构 | 语法 | 示例 | 说明 |
---|---|---|---|
Bash 无限 until | until false; do ... done | until false; do echo "Looping..."; done | 条件永远为假,无限循环 |
Ruby 无限 until | until false do ... end | until false do puts "Looping..." end | 类似 Bash,需手动退出 |
4. 特殊 until 循环(不同语言特性)
语言 | 结构 | 示例 | 说明 |
---|---|---|---|
Rust(无原生 until) | while !condition { ... } | while !(x >= 10) { ... } | 用 while 模拟 |
Kotlin(无原生 until) | while (!condition) { ... } | while (!(x >= 10)) { ... } | 与 Java 相同 |
Lua | repeat ... until condition | repeat ... until x >= 10 | Lua 的 repeat-until 是后测试循环 |
总结对比
循环类型 | 适用场景 | 典型语言 |
---|---|---|
原生 until | 条件为假时循环 | Bash、Ruby、Perl |
模拟 until | 用 while (!cond) 实现 | C/C++/Java/Python/Go |
无限 until | 手动控制退出 | until false (Bash/Ruby) |
后测试 until | 先执行后判断 | Lua (repeat-until ) |
2:until语句应用示例
为了进一步理解 until语句的结构和流程,掌握 until 语句在脚本中的实际使用,下面依次介绍两个脚本示例。
(1)计算1~50的和
在一些科学计算领域,经常会用到各种数的计算,自然数的求和操作是最简单的。本例中计算从 1 到58 的和,从1开始相加,采用循环的方式,每次循环后加 1,将得到的值加入计算的和中,数字运算采用的是 let 方式,直到加到 50 为止,具体的操作参考如下。
上述代码中,在 i 的值小于 50 之前,每次循环 i 的值加 1,并且求出 s的值。
(2)为指定用户发送在线消息
公司内部有一台 Linux 测试服务器,开发、测试、运维都在使用自己的账号连接登录到服务器上。当业务增加不能满足使用需求时,运维决定给服务器增加内存配置,要通知开发和测试人员保存数据退出,之后再关机升级内存,以应对业务的增加。
针对上面的需求,可编写一个名字为 until-user online to_write.sh 的 Shell脚本,用于给已登录用户发送消息,对用户进行检测,必须是系统内用户并且处于登录状态,通过 Linux 的 write 命令来发送消息,具体的脚本如下所示。
本章总结
本章详细介绍了 Shell编程中的循环语句与函数,为自动化脚本编写提供了强有力的工具。 循环语句:包括 for 循环、while 循环和 until循环。for 循环适用于处理预定义的列表,如批量操作文件或用户账号;while 循环和 until循环则根据条件执行循环体,分别适用于条件为真和条件为假的场景。这些循环语句极大地提高了脚本处理重复任务的效率。
总之,本章内容对于掌握 Shell编程的核心技能至关重要,是编写高效、可维护 Shell脚本的必备知识。