在这关于流程控制的最后一章中,我们将看看另一种 shell 循环构造。for 循环不同于 while 和 until 循环,因为 在循环中,它提供了一种处理序列的方式。这在编程时非常有用。因此在 bash 脚本中,for 循环是非常流行的构造。

实现一个 for 循环,很自然的,要用 for 命令。在现代版的 bash 中,有两种可用的 for 循环格式。

for: 传统 shell 格式

原来的 for 命令语法是:

for variable [in words]; do

commands

done

这里的 variable 是一个变量的名字,这个变量在循环执行期间会增加,words 是一个可选的条目列表, 其值会按顺序赋值给 variable,commands 是在每次循环迭代中要执行的命令。

在命令行中 for 命令是很有用的。我们可以很容易的说明它是如何工作的:

[me@linuxbox ~]$ for i in A B C D; do echo $i; done

A

B

C

D

在这个例子中,for 循环有一个四个单词的列表:“A”,“B”,“C”,和 “D”。由于这四个单词的列表,for 循环会执行四次。 每次循环执行的时候,就会有一个单词赋值给变量 i。在循环体内,我们有一个 echo 命令会显示 i 变量的值,来演示赋值结果。 正如 while 和 until 循环,done 关键字会关闭循环。

for 命令真正强大的功能是我们可以通过许多有趣的方式创建 words 列表。例如,通过花括号展开:

[me@linuxbox ~]$ for i in {A..D}; do echo $i; done

A

B

C

D

或者路径名展开:

[me@linuxbox ~]$ for i in distros*.txt; do echo $i; done

distros-by-date.txt

distros-dates.txt

distros-key-names.txt

distros-key-vernums.txt

distros-names.txt

distros.txt

distros-vernums.txt

distros-versions.txt

或者命令替换:

#!/bin/bash

# longest-word : find longest string in a file

while [[ -n $1 ]]; do

if [[ -r $1 ]]; thenmax_word=

max_len=0

fori in $(strings $1); dolen=$(echo $i | wc -c)

if (( len > max_len )); thenmax_len=$len

max_word=$i

fi

doneecho "$1: '$max_word' ($max_lencharacters)"

fishiftdone

在这个示例中,我们要在一个文件中查找最长的字符串。当在命令行中给出一个或多个文件名的时候, 该程序会使用 strings 程序(其包含在 GNU binutils 包中),为每一个文件产生一个可读的文本格式的 “words” 列表。 然后这个 for 循环依次处理每个单词,判断当前这个单词是否为目前为止找到的最长的一个。当循环结束的时候,显示出最长的单词。

如果省略掉 for 命令的可选项 words 部分,for 命令会默认处理位置参数。 我们将修改 longest-word 脚本,来使用这种方式:

#!/bin/bash

# longest-word2 : find longest string in a file

fori; do

if [[ -r $i ]]; thenmax_word=

max_len=0

forj in $(strings $i); dolen=$(echo $j | wc -c)

if (( len > max_len )); thenmax_len=$len

max_word=$j

fi

doneecho "$i: '$max_word' ($max_lencharacters)"

fi

done

正如我们所看到的,我们已经更改了最外围的循环,用 for 循环来代替 while 循环。通过省略 for 命令的 words 列表, 用位置参数替而代之。在循环体内,之前的变量 i 已经改为变量 j。同时 shift 命令也被淘汰掉了。

为什么是 i?

你可能已经注意到上面所列举的 for 循环的实例都选择 i 作为变量。为什么呢? 实际上没有具体原因,除了传统习惯。 for 循环使用的变量可以是任意有效的变量,但是 i 是最常用的一个,其次是 j 和 k。

这一传统的基础源于 Fortran 编程语言。在 Fortran 语言中,以字母 I,J,K,L 和 M 开头的未声明变量的类型 自动设为整形,而以其它字母开头的变量则为实数类型(带有小数的数字)。这种行为导致程序员使用变量 I,J,和 K 作为循环变量, 因为当需要一个临时变量(正如循环变量)的时候,使用它们工作量比较少。这也引出了如下基于 fortran 的俏皮话:

“神是实数,除非是声明的整数。”

for: C 语言格式

最新版本的 bash 已经添加了第二种格式的 for 命令语法,该语法相似于 C 语言中的 for 语法格式。 其它许多编程语言也支持这种格式:

for (( expression1; expression2; expression3 )); do

commands

done

这里的 expression1,expression2,和 expression3 都是算术表达式,commands 是每次循环迭代时要执行的命令。 在行为方面,这相当于以下构造形式:

(( expression1 ))

while (( expression2 )); do

commands

(( expression3 ))

done

expression1 用来初始化循环条件,expression2 用来决定循环结束的时间,还有在每次循环迭代的末尾会执行 expression3。

这里是一个典型应用:

#!/bin/bash

# simple_counter : demo of C style for command

for (( i=0; i<5; i=i+1 )); doecho $i

done

脚本执行之后,产生如下输出:

[me@linuxbox ~]$ simple_counter

0

1

2

3

4

在这个示例中,expression1 初始化变量 i 的值为0,expression2 允许循环继续执行只要变量 i 的值小于5, 还有每次循环迭代时,expression3 会把变量 i 的值加1。

C 语言格式的 for 循环对于需要一个数字序列的情况是很有用处的。我们将在接下来的两章中看到几个这样的应用实例。

总结

学习了 for 命令的知识,现在我们将对我们的 sys_info_page 脚本做最后的改进。 目前,这个 report_home_space 函数看起来像这样:

report_home_space () {

if [[ $(id -u) -eq 0 ]]; then

cat <

Home Space Utilization (All Users)

$(du -sh /home/*)

_EOF_

else

cat <

Home Space Utilization ($USER)

$(du -sh $HOME)

_EOF_

fi

return

}

下一步,我们将重写它,以便提供每个用户家目录的更详尽信息,并且包含用户家目录中文件和目录的总个数:

report_home_space () {

local format="%8s%10s%10s\n"

local i dir_list total_files total_dirs total_size user_name

if [[ $(id -u) -eq 0 ]]; then

dir_list=/home/*

user_name="All Users"

else

dir_list=$HOME

user_name=$USER

fi

echo "

Home Space Utilization ($user_name)

"

for i in $dir_list; do

total_files=$(find $i -type f | wc -l)

total_dirs=$(find $i -type d | wc -l)

total_size=$(du -sh $i | cut -f 1)

echo "

$i

"

echo "

"

printf "$format" "Dirs" "Files" "Size"

printf "$format" "----" "-----" "----"

printf "$format" $total_dirs $total_files $total_size

echo "

"

done

return

}

这次重写应用了目前为止我们学过的许多知识。我们仍然测试超级用户(superuser),但是我们在 if 语句块内 设置了一些随后会在 for 循环中用到的变量,来取代在 if 语句块内执行完备的动作集合。我们给 函数添加了几个本地变量,并且使用 printf 来格式化输出。

拓展阅读

分享到:

linux控制流程,Linux-流程控制:for 循环相关推荐

  1. 最全Linux驱动开发全流程详细解析(持续更新)

    Linux驱动开发详细解析 一.驱动概念 驱动与底层硬件直接打交道,充当了硬件与应用软件中间的桥梁. 具体任务 读写设备寄存器(实现控制的方式) 完成设备的轮询.中断处理.DMA通信(CPU与外设通信 ...

  2. Linux下服务器端开发流程及相关工具介绍(C++)

    原文:Linux下服务器端开发流程及相关工具介绍(C++) 去年刚毕业来公司后,做为新人,发现很多东西都没有文档,各种工具和地址都是口口相传的,而且很多时候都是不知道有哪些工具可以使用,所以当时就想把 ...

  3. Linux系统管理-开机启动流程

    Linux系统管理-开机启动流程 文章目录 Linux系统管理-开机启动流程 CentoOS6的开机启动流程 CentOS6忘记root密码 Linux的关机指令 CentOS7的开机启动流程 Cen ...

  4. 嵌入式Linux系统环境搭建全流程-4412友善之臂开发板

    4412友善之臂开发板-Linux系统环境搭建全流程 ​ 没错,这篇确实值得一看!可能是由于我稍微会一点点哈,就有好多小伙伴就找我帮他们搭建环境,但Linux中的以及开发版连接,与烧写程序中的整个环境 ...

  5. Linux挖矿病毒清理流程

    Linux挖矿病毒清理流程 1.前言: 根据阿里云快讯病毒公布: Redis RCE导致h2Miner蠕虫病毒,其利用Redis未授权或弱口令作为入口,使用主从同步的方式从恶意服务器上同步恶意modu ...

  6. vbs结束进程代码_物联网学习教程—Linux系统编程之进程控制

    Linux系统编程之进程控制 一.结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳 ...

  7. linux驱动程序是什么,简述一个Linux驱动程序的主要流程与功能

    1. 简述一个Linux驱动程序的主要流程与功能. 2. 请列举一个软件中时间换空间或者空间换时间的例子. void swap(int a,int b) { int c; c=a;a=b;b=a; } ...

  8. linux除了eeprom其他的保存方法,linux的EEPROM的读写控制.doc

    毕业设计[论文]题目:基于linux的EEPROM的读写控制毕业论文(设计)原创性声明 本人所呈交的毕业论文(设计)是我在导师的指导下进行的研究工作及取得的研究成果.据我所知,除文中已经注明引用的内容 ...

  9. linux的每次IO大小控制,linux文件io缓冲

    linux文件io缓冲 出于速度和效率考虑,系统io调用(即内核)和标准 C语言库的io函数(即 stdin 函数)在操作磁盘文件时会对数据进行缓冲. read(),write()系统调用在操作磁盘文 ...

  10. 10 Linux引导过程和服务控制

    Linux引导过程和服务控制 一 引导过程 开机自检→MBR引导→GRUB菜单→加载内核→运行INIT进程 →读取配置文件 1 开机自检 根据主板bios中的设置对CPU.内存.显卡.等硬件设备进行初 ...

最新文章

  1. 那位13岁就当上老板的开发者是如何炼成的?
  2. linux 系统负载
  3. java全写_Java 写文件
  4. 【django】模型
  5. 高斯过程回归python_基于python的高斯过程回归训练集数据扩充
  6. Linux主要shell命令详解
  7. python替换所有标点符号 正则_python 把标点符号替换为空
  8. C++ 中export 关键字的尴尬处境
  9. python画图库matplotlib:初识
  10. 让计划任务生成的文件中包含当前日期
  11. Docker容器虚拟化与传统虚拟机比较
  12. 企业数据安全防护不可忽视,数据丢失/损坏如何处理?
  13. pycharm写python三个双引号_Pycharm中批量添加单引号,双引号的方法(爬虫Headers中批量加引号)...
  14. 1. 喵喵宠物管理系统需求分析
  15. 网络设备商网管软件解决方案
  16. 【CLP】Conic Linear Programming Duality
  17. 阿里巴巴在知乎上又出事了
  18. 技术寡头争霸传之:控制开源工具,就控制了整个生态
  19. 开根号的笔算算法图解_一个数的开根号怎么计算
  20. pandas将excel中多行多列单元格含有多个值拆分为一对一单行显示的方法(explode函数)

热门文章

  1. 设计模式 策略模式
  2. atitit.微信项目开发效率慢的一些总结
  3. HDU4007 Dave [杂题]
  4. 转:Oracle 应用服务器 MapViewer 10.1.2截图
  5. 软件架构解读与架构师角色培养——希赛嘉宾聊天实录
  6. SDN控制器构建原理方法—Vecloud
  7. Python学习教程实用技法:通过公共键对字典列表排序—itemgetter
  8. Netty入门(七)使用SSL/TLS加密Netty程序
  9. 从程序集/类库下面取文件
  10. Tsung MQTT协议简介及MQTT xml文档配置介绍