[转帖]流程控制:for 循环
流程控制:for 循环
http://wiki.jikexueyuan.com/project/linux-command/chap34.html need more study need more knowledge
在这关于流程控制的最后一章中,我们将看看另一种 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 ]]; then
max_word=
max_len=0
for i in $(strings $1); do
len=$(echo $i | wc -c)
if (( len > max_len )); then
max_len=$len
max_word=$i
fi
done
echo "$1: '$max_word' ($max_len characters)"
fi
shift
done
在这个示例中,我们要在一个文件中查找最长的字符串。当在命令行中给出一个或多个文件名的时候, 该程序会使用 strings 程序(其包含在 GNU binutils 包中),为每一个文件产生一个可读的文本格式的 “words” 列表。 然后这个 for 循环依次处理每个单词,判断当前这个单词是否为目前为止找到的最长的一个。当循环结束的时候,显示出最长的单词。
如果省略掉 for 命令的可选项 words 部分,for 命令会默认处理位置参数。 我们将修改 longest-word 脚本,来使用这种方式:
#!/bin/bash
# longest-word2 : find longest string in a file
for i; do
if [[ -r $i ]]; then
max_word=
max_len=0
for j in $(strings $i); do
len=$(echo $j | wc -c)
if (( len > max_len )); then
max_len=$len
max_word=$j
fi
done
echo "$i: '$max_word' ($max_len characters)"
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 )); do
echo $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 <<- _EOF_
<H2>Home Space Utilization (All Users)</H2>
<PRE>$(du -sh /home/*)</PRE>
_EOF_
else
cat <<- _EOF_
<H2>Home Space Utilization ($USER)</H2>
<PRE>$(du -sh $HOME)</PRE>
_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 "<H2>Home Space Utilization ($user_name)</H2>"
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 "<H3>$i</H3>"
echo "<PRE>"
printf "$format" "Dirs" "Files" "Size"
printf "$format" "----" "-----" "----"
printf "$format" $total_dirs $total_files $total_size
echo "</PRE>"
done
return
}
这次重写应用了目前为止我们学过的许多知识。我们仍然测试超级用户(superuser),但是我们在 if 语句块内 设置了一些随后会在 for 循环中用到的变量,来取代在 if 语句块内执行完备的动作集合。我们添加了给 函数添加了几个本地变量,并且使用 printf 来格式化输出。
拓展阅读
《高级 Bash 脚本指南》有一章关于循环的内容,其中列举了各种各样的 for 循环实例:
《Bash 参考手册》描述了循环复合命令,包括了 for 循环:
http://www.gnu.org/software/bash/manual/bashref.html#Looping-Constructs
[转帖]流程控制:for 循环的更多相关文章
- python流程控制for循环
流程控制 for循环 #首先我们用一例子看下用while循环取出列表中值的方法 l=['a','b','c'] i=0 while i<len(l): print(l[i]) i+=1 #whi ...
- python全栈 流程控制;while 循环 格式化输出 运算符 及编码
python全栈开发 1循环 2break和continue的区别 3格式化输出 4运算符 5编码 一.流程控制while循环 while条件: 代码块(循环体) 1.死循环; while True; ...
- Python之流程控制——while循环
Python之流程控制--while循环 一.语法 while 条件: 执行代码 while就是当的意思,它指当其后面的条件成立,就执行while下面的代码. 例:写一个从0打印到10的程序 coun ...
- ansible-playbook流程控制-loops循环使用
1. ansible-playbook流程控制-loops循环使用 有时你想要多次重复任务.在计算机编程中,这称为循环.common ansible循环包括使用文件模块更改多个文件和/或目录的所 ...
- PHP丨PHP基础知识之流程控制WHILE循环「理论篇」
昨天讲完FOR循环今天来讲讲他的兄弟WHILE循环!进入正题: while是计算机的一种基本循环模式.当满足条件时进入循环,进入循环后,当条件不满足时,跳出循环.while语句的一般表达式为:whil ...
- 053 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 15 流程控制知识总结
053 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 15 流程控制知识总结 本文知识点: 流程控制知识总结 流程控制知识总结 选择结构语句 循环结构语句 ...
- 052 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 14 Eclipse下程序调试——debug2 多断点调试程序
052 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 14 Eclipse下程序调试--debug2 多断点调试程序 本文知识点: Eclipse下程序调 ...
- 051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试——debug入门1
051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试--debug入门1 本文知识点: 程序调试--debug入门1 程序 ...
- 050 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 12 continue语句
050 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 12 continue语句 本文知识点:continue语句 continue语句 continue ...
- 049 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 11 break语句
049 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 11 break语句 本文知识点:break语句 break语句 break语句前情回顾 1.swi ...
随机推荐
- 死磕 java集合之TreeSet源码分析
问题 (1)TreeSet真的是使用TreeMap来存储元素的吗? (2)TreeSet是有序的吗? (3)TreeSet和LinkedHashSet有何不同? 简介 TreeSet底层是采用Tree ...
- SQLI LABS Advanced Part(23-37) WriteUp
继续继续!这里是高级部分! less-23: 提示输入id参数,尝试: ?id=1' and '1 返回的结果与?id=1相同,所以可以直接利用了. ?id=1' order by 5# 可是页面返回 ...
- Koa 中的错误处理
不像 express 中在末尾处注册一个声明为 (err, req, res, next) 中间件的方式,koa 刚好相反,在开头进行注册. app.use(async (ctx, next) =&g ...
- 【java线程池】
一.概述 1.线程池的优点 ①降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗: ②提高系统响应速度,当有任务到达时,无需等待新线程的创建便能立即执行: ③方便线程并发数的管控,线 ...
- 前端笔记之JavaScript面向对象(二)内置构造函数&相关方法|属性|运算符&继承&面向对象
一.复习 1.1复习上下文 函数的调用方式 上下文 fun() window obj.fun() obj box.onclick = fun box setInterval(fun,1000) set ...
- C# 委托链(多播委托)
委托既可以封装一个方法,又可以对同一类型的方法进行封装,它就是多播委托 using System; using System.Collections.Generic; using System.Lin ...
- .net core入门-发布及部署_异常(处理程序“aspNetCore”在其模块列表中有一个错误模块“AspNetCoreModuleV2")处理
备注:本人使用开发工具:VS2017,.NET Core 2.2,其中VS2017原本自带2.1,我单独从官网下载了2.2的程序集安装包,但是没有下配套的运行环境,运行项目时出了一个问题. 以下是我在 ...
- C# 创建、更改Excel命名区域(NamedRange)
创建命名区域是指给选定的某个单元格或多个单元格区域设置名称,目的是方便我们在文件中的其他地方对该单元格区域进行引用能够简化公式引用或者方便数据管理.下面记录了具体的C#示例代码.这里创建命名区域分为了 ...
- 学习笔记—MySQL基础
数据库的介绍 mysql数据库介绍 开放源码的轻量级关系型数据库管理系统,体积小.速度快.操作便捷. 数据库的启动和连接 mysql数据库启动 在终端输入以下命令,启动mysql服务器 service ...
- 第八课 表格 html5学习3
表格用来处理表格式数据的,不是用来布局的. 一.基本语法格式 <table> <tr> 行标签 <td></td> 单元格标签 </tr> ...