【shell笔记>脚本】结构化命令之循环控制

内容

  • for循环语句
  • until迭代语句使用while语句
  • 循环
  • 重定向循环的输出

这一节我们来了解如何重复一些过程和命令,也就是循环执行一组命令直到达到了某个特定条件。

for命令

基本格式:

for var in list
do
    commands
done

也可以

for var in list; do

分号只用来分隔命令的,让代码更简约。

来个简单例子:

wsx@wsx-ubuntu:~/script_learn$ cat test1
#!/bin/bash
# basic for command

for test in Alabama Alaska Arizona Arkansas California Colorado
do 
    echo The next state is $test
done

wsx@wsx-ubuntu:~/script_learn$ ./test1
The next state is Alabama
The next state is Alaska
The next state is Arizona
The next state is Arkansas
The next state is California
The next state is Colorado

这里操作基本和其他语言一致(格式不同),不多讲啦。

在读取列表中的复杂值时,我们可能会遇到问题。比如下面这个例子:

wsx@wsx-ubuntu:~/script_learn$ cat badtest1 
#!/bin/bash
# another example of how not to use the for command

for test in I don't know if this'll work
do
    echo "word:$test"
done

wsx@wsx-ubuntu:~/script_learn$ ./badtest1 
word:I
word:dont know if thisll
word:work

我们可以看到shell看到了列表值中的单引号尝试使用它们来定义一个单独的数据值。

这里有两种解决办法:

  • 使用转义字符将单引号转义
  • 使用双引号来定义用到单引号的值

我们将这两种解决办法同时用到上个例子:

wsx@wsx-ubuntu:~/script_learn$ cat test2
#! /bin/bash
# another example of how not to use the for command

for test in I don\'t know if "this'll" work; do
echo  "word:$test"
done
wsx@wsx-ubuntu:~/script_learn$ ./test2
word:I
word:don't
word:know
word:if
word:this'll
word:work

我们可能明白了for循环是假定每个值是用空格分隔的,所以当有包含空格的数据时,我们需要用双引号括起来。

通常我们会将列表值存储在一个变量中,然后通过遍历变量的方式遍历了其内容的的列表。

看看怎么完成这个任务:

wsx@wsx-ubuntu:~/script_learn$ cat test3
#!/bin/bash

# using a variable to hold the list
list="Alabama Alaska Arizona Arkansas Colorado"
list=$list" Connecticut" # 在尾部拼接文本

for state in $list; do
  echo "Have you ever visited $state?"
done

wsx@wsx-ubuntu:~/script_learn$ ./test3
Have you ever visited Alabama?
Have you ever visited Alaska?
Have you ever visited Arizona?
Have you ever visited Arkansas?
Have you ever visited Colorado?
Have you ever visited Connecticut?

注意,代码中还用了另一个赋值语句向$list变量包含的已有列表中添加了一个值。这是在已有文本字符串尾部添加文本的一种常用方法。

我们还可以用命令来输出我们需要的列表内容

wsx@wsx-ubuntu:~/script_learn$ cat test4
#!/bin/bash
# reading values from a file

file="states"

for state in $(cat $file)
do
    echo "Visit beautiful $state"
done

wsx@wsx-ubuntu:~/script_learn$ cat states
Alabama
Alaska
Arizona
Arkansas
Colorado
Connecticut
Delaware
Florida
Georgia
wsx@wsx-ubuntu:~/script_learn$ ./test4
Visit beautiful Alabama
Visit beautiful Alaska
Visit beautiful Arizona
Visit beautiful Arkansas
Visit beautiful Colorado
Visit beautiful Connecticut
Visit beautiful Delaware
Visit beautiful Florida
Visit beautiful Georgia

更改字段分隔符

环境变量IFS,也叫作字段分隔符。它定义了bash shell用作字段分隔符的一系列字符。默认情况下,bash shell会将空格、制表符和换行符当作字段分隔符。

如果想修改IFS的值,比如使其只能识别换行符,我们可以将下面这行代码加入脚本:

IFS=$'\n'

在处理大量脚本时,我们可能只在某一部分使用其他的分隔符,这时候可以先保存原有的IFS值,然后修改,最后恢复:

IFS.OLD=$IFS
IFS=$'\n'
<在代码中使用新的IFS值>
IFS=$IFS.OLD

假如我们要遍历一个文件中用冒号分隔的值:

IFS=:

假如要指定多个IFS字符,只要将它们的赋值行串起来:

IFS=$'\n':;"

这个赋值会将换行符、冒号、分号以及双引号作为字段分隔符。

用通配符读取目录

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

我拿我的一个目录来尝试一下:

wsx@wsx-ubuntu:~/script_learn$ cat test5
#!/bin/bash

# iterate through all the files in a directory

for file in /home/wsx/python_learn/*
do
  if [ -d "$file" ]
  then
    echo "$file is a directory"
  elif [ -f "$file" ]
  then
    echo "$file is a file"
  fi
done
wsx@wsx-ubuntu:~/script_learn$ ./test5
/home/wsx/python_learn/athletelist.py is a file
/home/wsx/python_learn/athletemodel.py is a file
/home/wsx/python_learn/ch2_data_input.py is a file
/home/wsx/python_learn/chapter5_first.py is a file
/home/wsx/python_learn/chapter6_first.py is a file
/home/wsx/python_learn/chapter6_second.py is a file
/home/wsx/python_learn/chapter6_third.py is a file
/home/wsx/python_learn/coinFlips.py is a file
/home/wsx/python_learn/Dive_into_python is a directory

注意:第一个方括号之后和第二个方括号之前必须加上一个空格,否则会报错。

在Linux中,目录名和文件名中包含空格是合法的,所以将$file变量用双引号圈起来。当然,大家尽量不要让文件或目录包含空格,不然很容易出问题(命令会把空格当做文件的分隔符)。

C语言风格的for命令

C语言风格的for命令看起来如下:

for (( a = 1; a < 10; a++ ))

值得注意的是,这里有些部分没有遵循bash shell标准的for命令:

  • 变量赋值可以有空格;
  • 条件中的变量不以美元符开头;
  • 迭代过程的算式未用expr命令格式。

在使用这种格式时要小心,不同的格式不注意就会出错。

下面举个例子:

wsx@wsx-ubuntu:~/script_learn$ cat test6
#!/bin/bash

# testing the C-style for loop

for (( i=1; i <= 10; i++ ))
do
  echo "The next number is $i"
done

wsx@wsx-ubuntu:~/script_learn$ ./test6
The next number is 1
The next number is 2
The next number is 3
The next number is 4
The next number is 5
The next number is 6
The next number is 7
The next number is 8
The next number is 9
The next number is 10

while命令

while命令的格式为:

while test command
do 
  other commands
done

while命令某种意义上是if-then语句和for循环的混杂体。注意,这里while后面接的也是命令。while命令允许定义一个要测试的命令,然后循环执行一组命令,只要定义的测试命令返回的是退出状态码是0(类似一般语言中 的TRUE)。直到非0时退出循环。

while命令中定义的test commandif-then语句中的格式一模一样。可以使用任何普通的bash shell命令,或者用test命令进行条件测试,比如测试变量值。

最常见的用法是用方括号来检查循环命令中用到的shell变量的值。

wangsx@SC-201708020022:~/tmp$ cat test
#/bin/bash
# while command test

var1=10
while [ $var1 -gt 0 ]
do
        echo $var1
        var1=$[ $var1 - 1 ]
done

wangsx@SC-201708020022:~/tmp$ ./test
10
9
8
7
6
5
4
3
2
1

使用多个测试命令
while命令允许我们在while语句行中定义多个测试命令。只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。
比如while echo $var1 [ $var1 -ge 0 ]检测的就是后面方括号命令的退出状态码。

until命令

until命令和while命令工作的方式完全相反。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令。一旦测试命令返回了退出状态码0,循环就结束了。

until test command
do
  other commands
done

一个例子:

wangsx@SC-201708020022:~/tmp$ cat test12  
#!/bin/bash                               
# using the until command                 
                                          
var1=100                                  
                                          
until [ $var1 -eq 0 ]                     
do                                        
        echo $var1                        
        var1=$[ $var1 - 25 ]              
done                                      
                                          
wangsx@SC-201708020022:~/tmp$ ./test12    
100                                       
75                                        
50                                        
25                                        

同样地,在until命令中放入多个测试命令时也要注意(类似while)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容

  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,127评论 2 34
  • 基础命令 主要的命令和快捷键 Linux系统命令由三部分组成:cmd + [options]+[operation...
    485b1aca799e阅读 1,085评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,579评论 18 139
  • 一直觉得,有些人注定你会相遇,有些事注定会发生。 那时候,我拖着行李箱和母亲一起去一中报到。我就遇见了...
    夕月不语阅读 378评论 1 0
  • 现在的家有一个向往已久的小院,我种了很多菜,第一次种菜,犯了很多错。当隔壁家的菠菜开始吃的时候,我的菠菜才露...
    飞舞的红叶阅读 412评论 1 3