Linux#7 Shell结构化循环命令进阶

碎片时间x体系学习

这是第143篇原创;距2019年还有175天

00

Shell的结构化循环命令

上文中我们知道了如何通过检查命令输出和变量的值来改变shell脚本执行的流程。本文中,我们将会了解到如何重复一些过程命令,也就是循环执行一组命令直到达到了某个特定条件。

01

使用for命令

格式:

for var in list

do

commands

done

功能:

允许创建一个遍历一系列值的循环。每个迭代都通过一个该系列中的值执行一组预定义的命令。在list参数中提供了迭代中要用的一系列值,以下将分别介绍几种不同的途径来指定列表中的值。

1.1 读取列表中的值

for命令最基本的用法就是遍历for命令自身定义的一系列值。示例如下:

从示例中可以看出,for命令是用空格来划分列表中的每个值。var变量在每次循环都会从列表中获取一个新值,一直到最后一次迭代为止。

注意事项:

列表中变量如何存在特殊数据,需要进行特殊处理

变量中如果存在单引号,那么可以采用转义字符(反斜线)来将单引号转义;也可以采用双引号来定义用到单引号的值

变量中如果存在空格,那么可以采用双引号将这些值圈起来

也可以把上述的列表值存放在一个shell变量中,效果是一致的

1.2 从命令读取值

如上所示,我们可以用一个变量去存储列表值;另外,我们也可以将命令的结果输出作为列表值。具体使用过程中,可以使用反引号来执行任何能产生输出的命令,然后在for命令中使用该命令的输出。示例如下:

如上所示,当我们执行ls $path(用反引号圈起来)时,命令的输出结果的信息是以空格作为分割的列表,for命令正好可以遍历列表中的每个值。

1.3 用通配符读取目录

此外,我们还可以用for命令来自动遍历目录,在此过程中,我们需要在文件名或目录名中使用通配符。它会强制shell使用文件扩展匹配。文件扩展匹配是生成匹配指定的通配符的文件名或路径名的过程。

如上所示,我们利用了*实现了对文件扩展匹配,会实现对特定目录下所有文件的遍历,然后利用测试判断该文件是目录类型、普通文件类型还是其他类型。

注意:Linux中的文件名称是可以包含空格的;为此,要容纳这种值,我们应该用引号把这种值圈起来。如果不这样做,遇到含有空格的目录名或文件名时会产生错误。

1.4 更改字段分割符

Linux有一个特殊的环境变量IFS,称为内部字段分隔符。IFS环境变量定义了bash shell用作字段分隔符的一系列字符。默认情况下,会将下列字符当做字段分隔符:

空格

制表符

换行符

如果bash shell在数据中看到了这些字符中的任意一个,它就会假定你在列表中开始了一个新的数据段。为了让shell脚本在特定的语句上下文中只认一个字符分隔符,我们可以通过修改IFS的值进行指定。比如用语句IFS=$'#'可指定#号为列表中的字符分隔符,完整示例如下:

注意事项:

上述为典型脚本。我们在特定上下文中可能需要通过指定IFS的为字符分隔符,一般我们会事先将IFS的旧值进行存储,使用完成后,我们再恢复IFS的原值。这会为脚本中后面的操作保证IFS的值恢复到了默认值。

上例中我们指定IFS为唯一值,也可指定为多个值,只要将它们在赋值行串起来就行:IFS=$':;\n';通过该语句,我们就指定了冒号、分号、换行符为字段分割符。

02

使用while命令

格式:

while test command

do

commands

done

功能:

while命令是if-then语句和for循环的混合体,它可以允许你定义一个要测试的命令command,只要定义的测试命令返回值是退出状态码0,它就会一直循环执行一组命令;当返回值为非0,就会退出循环。

注意事项:

格式中的command 可以是一组组合命令,但是只有最后一个测试命令的状态退出码会被用来决定什么时候结束循环,示例如下:

03

使用until命令

格式:

until test command

do

commands

done

功能:

until命令和while命令的工作方式在测试命令条件的时候正好完全相反。当until的测试命令command退出状态码为非0时,它就会一直循环执行一组命令;当返回值为0时,就会退出循环。

注意事项:

同while命令,格式中的command 可以是一组组合命令,但是只有最后一个测试命令的状态退出码会被用来决定什么时候结束循环。

04

循环控制命令

汽车一旦启动,我们需要通过刹车、方向盘对汽车进行控制。同理,循环命令一旦启动,我们也需要通过指令(命令)实现对循环进行有效控制。以下命令可以帮助我们实现对循环的控制:

break命令

continue命令

4.1 break命令

我们可以利用break命令直接退出正在进行的for、while、until循环,转而去执行循环体外的语句。考虑到循环有单层、多层循环之分,该命令在不同的循环上下文有不同的作用。

跳出当前正在执行的循环体对应的循环

如果执行break n,n说明了跳出的循环层级。默认情况下,n为1,表明跳出当前的循环;如果将n设置为2,则该命令会停止上一级的外部循环;示例如下:

4.2 continue命令

continu命令会提早结束执行循环内部的命令,但并不完全终止整个循环。

和break命令类似。如果执行continue n,n定义了要继续的循环层级;示例如下:

注意事项:

在循环执行体中,一定要有能改变测试条件的功能,否则就可能会出现死循环,如上述两个例子中,在内层循环中的测试条件是对var2进行判断,但是内层循环中并未有改变var2的值,这是有死循环的潜在问题的,好在我们用break、continu命令规避了该问题

05

处理循环的输出

我们可以在shell脚本的循环控制done命令后增加对循环结果输出的处理;通常有两种处理方式,分别实例如下:

重定向到文件中

通过管道将循环的结果管接给另一个命令

06

小结

综上,本文对shell中提供的三种循环命令及循环控制进行了介绍。

for命令允许遍历一系列的值,这些值的来源可以是列表、变量、命令结果、文件/目录通配符等。

while命令提供了基于命令条件的循环,使用普通命令或test命令来测试循环的条件。只要在命令或条件产生退出状态码0时,while循环才会继续遍历指定的一组命令。

until命令也提供了遍历命令的一种方法,但它的迭代是建立在命令或条件产生退出状态码非0时,until循环才会继续遍历指定的一组命令;如果状态码为0,则退出until执行。

此外,在shell脚本中可组合循环,生成多个层级的循环;bash shell提供了continue和break命令,基于循环内的不同值改变通常的循环过程的流程。

bash shell还允许使用标准的命令重定向和管道来改变循环的输出。可以使用重定向将循环的结果重定向到一个文件,或使用管道将循环的结果重定向给另一个命令。

在下文中,将会对shell脚本与用户交互方式进行介绍,敬请期待!

One More Thing

推荐1:技术与软技能干货分享

上文1:Linux#6 shell的结构化命令

上文2:Linux#5 shell编程快速入门

近期,我和活跃在业界的一线技术老司机们共同开通了知识星球,——一个与公众号有别,但又一脉相承的技术圈、认知圈:公众号会一如既往地进行知识分享,知识星球则坚持关注解决问题与动手实践,主要涉及Java后端、Linux、Python、Android等技术领域,问题很广、方法很多、思绪很快,希望我们能够在这里驻足思考、交流、沉淀、提升。

你负责认真,我们负责帮你解决问题,让改变发生;欢迎大家扫码加入我们的星球。期待 2018,在程序猿成长的道路上,共同进化!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180709B06RXR00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券