流程控制: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 来格式化输出。

拓展阅读

[转帖]流程控制:for 循环的更多相关文章

  1. python流程控制for循环

    流程控制 for循环 #首先我们用一例子看下用while循环取出列表中值的方法 l=['a','b','c'] i=0 while i<len(l): print(l[i]) i+=1 #whi ...

  2. python全栈 流程控制;while 循环 格式化输出 运算符 及编码

    python全栈开发 1循环 2break和continue的区别 3格式化输出 4运算符 5编码 一.流程控制while循环 while条件: 代码块(循环体) 1.死循环; while True; ...

  3. Python之流程控制——while循环

    Python之流程控制--while循环 一.语法 while 条件: 执行代码 while就是当的意思,它指当其后面的条件成立,就执行while下面的代码. 例:写一个从0打印到10的程序 coun ...

  4. ansible-playbook流程控制-loops循环使用

    1. ansible-playbook流程控制-loops循环使用    有时你想要多次重复任务.在计算机编程中,这称为循环.common ansible循环包括使用文件模块更改多个文件和/或目录的所 ...

  5. PHP丨PHP基础知识之流程控制WHILE循环「理论篇」

    昨天讲完FOR循环今天来讲讲他的兄弟WHILE循环!进入正题: while是计算机的一种基本循环模式.当满足条件时进入循环,进入循环后,当条件不满足时,跳出循环.while语句的一般表达式为:whil ...

  6. 053 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 15 流程控制知识总结

    053 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 15 流程控制知识总结 本文知识点: 流程控制知识总结 流程控制知识总结 选择结构语句 循环结构语句 ...

  7. 052 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 14 Eclipse下程序调试——debug2 多断点调试程序

    052 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 14 Eclipse下程序调试--debug2 多断点调试程序 本文知识点: Eclipse下程序调 ...

  8. 051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试——debug入门1

    051 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 13 Eclipse下程序调试--debug入门1 本文知识点: 程序调试--debug入门1 程序 ...

  9. 050 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 12 continue语句

    050 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 12 continue语句 本文知识点:continue语句 continue语句 continue ...

  10. 049 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 11 break语句

    049 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 11 break语句 本文知识点:break语句 break语句 break语句前情回顾 1.swi ...

随机推荐

  1. 用python读文件如.c文件生成excel文件

    记录一下,如何实现的,代码如下: #!/usr/bin/env python # coding=utf-8 # 打开文件 import xlwt import re import sys bookfi ...

  2. h2engine游戏服务器设计之聊天室示例

    游戏服务器设计之聊天室示例 简介 h2engine引擎建群以后,有热心网友向我反馈,想尝试h2engine但是没有服务器开发经验觉得无从入手,希望我能提供一个简单明了的示例.由于前一段时间工作实在忙碌 ...

  3. stylus 详解与引入

    Stylus介绍及特点Stylus 是一个基于Node.js的CSS的预处理框架,诞生于2010年,比较年轻,可以说是一种新型语言,其本质上做的事情与 Sass/LESS 等类似, 可以以近似脚本的方 ...

  4. springcloud情操陶冶-bootstrapContext(三)

    本文则将重点阐述context板块的自动配置类,观察其相关的特性并作相应的总结 自动配置类 直接查看cloudcontext板块下的spring.factories对应的EnableAutoConfi ...

  5. 使用IO流写文件的一些骚操作

    序言 当需要对文件进行操作时,使用IO流是不能避免的操作:比如业务中需要存储一些请求的响应结果中的一些内容.当所需处理的文件过大时,如果频繁的关闭文件流,会造成很大的开销,何时关闭?往往会造成比较大的 ...

  6. Java 合并、拆分PDF文档

    处理PDF文档时,我们可以通过合并的方式,来任意组几个不同的PDF文件或者通过拆分将一个文件分解成多个子文件,这样的好处是对文档的存储.管理很方便.下面将通过Java程序代码介绍具体的PDF合并.拆分 ...

  7. 输入框中的空"",0,null的判断

    改了一个小项目,里面有一个小的问题他们是这样提需求的.两个输入框,第一个输入框里面,输入的内容会对第二个输入框中的内容产生影响.具体是这样的:如果第一个输入框中的值不是“0”,那么第二个输入框就不能填 ...

  8. IDEA 安装配置可视化 MongDB 插件

    IDEA 安装配置可视化 MongDB 插件 1.安装MongoDB插件 打开 IDEA ,file --> settings --> plugins,在右边搜索栏中输入Mongo,点击 ...

  9. Windows有点腻了?不如试试Ubuntu.

    最近在接触Python. 因为担心环境会向Java一样,很容易影响当前的工作电脑. 所以准备搭建一台虚拟机,不过Windows的尺寸是在太大了.所以,选择安装Ubuntu. Ubuntu官方网站地址: ...

  10. 亿级流量场景下,大型架构设计实现【全文检索高级搜索---ElasticSearch篇】-- 中

    1.Elasticsearch的基础分布式架构: 1.Elasticsearch对复杂分布式机制的透明隐藏特性2.Elasticsearch的垂直扩容与水平扩容3.增减或减少节点时的数据rebalan ...