Shell基础之控制流结构

一、控制结构

几乎所有的脚本里都有某种流控制结构,很少有例外。流控制是什么?假定有一个脚本,包含下列几个命令:

#!/bin/sh
# make a directory
mkdir /home/dave/mydocs
# copy all doc files
cp *.docs /home/dave/docs
# delete all doc files
rm *.docs

上述脚本问题出在哪里?如果目录创建失败或目录创建成功文件拷贝失败,如何处理?这里需要从不同的目录中拷贝不同的文件。必须在命令执行前或最后的命令退出前决定处理方法。shell会提供一系列命令声明语句等补救措施来帮助你在命令成功或失败时,或需要处理一个命令清单时采取正确的动作。这些命令语句大概分两类:

1、循环和流控制

  • if 语句

    提供条件测试。测试可以基于各种条件。例如文件的权限、长度、数值或字符串的比较。这些测试返回值或者为真(0),或者为假(1)。基于此结果,可以进行相关操作。在讲到条件测试时已经涉及了一些测试语法。

  • case语句

    允许匹配模式、单词或值。一旦模式或值匹配,就可以基这个匹配条件作其他声明。

2、循环

循环或跳转是一系列命令的重复执行过程,本书提到了3种循环语句:

  • for 循环

    每次处理依次列表内信息,直至循环耗尽。

  • Until 循环

    此循环语句不常使用, until循环直至条件为真。条件部分在循环末尾部分。

  • While 循环

    while循环当条件为真时,循环执行,条件部分在循环头。
    流控制语句的任何循环均可嵌套使用,例如可以在一个for循环中嵌入另一个for循环。


二、实例讲解

现在开始讲解循环和控制流,并举一些脚本实例。

从现在起,脚本中语句使用LINUX或BSD版本,也就是说使用echo方法echo -e -n,意即从echo结尾中下一行执行命令。

1、grep输出检查

不必拘泥于变量或数值测试,也可以测知系统命令是否成功返回。对grep使用if语句找出,grep是否成功返回信息。下面的例子中grep用于查看Dave是否在数据文件data.file中,注意’Dave>‘用于精确匹配。
[root@localhost ~]# cat grepif.sh
#!/bin/sh
# grepif.sh
if grep 'Dave\>' data.file > /dev/null 2>&1
then
               echo "Great Dave is in the file"
else
               echo "No Dave is not in the file"
fi
[root@localhost ~]# ./grepif.sh
No Dave is not in the file

2、用变量测试grep输出

正像前面看到的,可以用grep作字符串操作。下面的脚本中,用户输入一个名字列表,grep在变量中查找,要求其包含人名Peter
[root@localhost ~]# cat grepstr.sh
#!/bin/sh
# grepstr
echo -n "Enter a list of names:"
read list
if echo $list | grep "Peter" > /dev/null 2>&1
then
               echo "Peter is here"
               # could do some processing here...
else
               echo "Peter's not in the list. No comment!"
fi
[root@localhost ~]# ./grepstr.sh
Enter a list of names:John Louise Peter James
Peter is here

3、文件拷贝输出检查

下面测试文件拷贝是否正常,如果cp命令并没有拷贝文件myfile到myfile.bak,则打印错误信息。注意错误信息中basename $0打印脚本名。如果脚本错误退出,一个好习惯是显示脚本名并将之定向到标准错误中。用户应该知道产生错误的脚本名。
 [root@localhost ~]# cat ifcp.sh
#!/bin/sh
# ifcp.sh
if cp myfile myfile.bak; then
               echo "good copy"
else
               echo "`basename $0`: error could not copy the file" >&2
fi
[root@localhost ~]# ./ifcp.sh
cp: cannot stat `myfile': No such file or directory
ifcp.sh: error could not copy the file
注意,文件可能没找到,系统也产生本身的错误信息,这类错误信息可能与输出混在一起。既然已经显示系统错误信息获知脚本失败,就没必要显示两次。要去除系统产生的错误和系统输出,只需简单的将标准错误和输出重定向即可。修改脚本为: >/dev/null 2>&1。
[root@localhost ~]# cat ifcp.sh
#!/bin/sh
# ifcp.sh
if cp myfile myfile.bak > /dev/null 2>&1; then
               echo "good copy"
else
               echo "`basename $0`: error could not copy the file" >&2
fi
[root@localhost ~]# ./ifcp.sh
ifcp.sh: error could not copy the file
上面当中>/dev/null表示任何标准输出都定向到那个无尽的“黑洞”/de/null中,然后2>&1表示错误输出也是到/dev/null中,&1表示前面的那个/dev/null,脚本运行时,所有输出包括错误重定向至系统垃圾堆。

4、当前目录测试

当运行一些管理脚本时,可能要在根目录下运行它,特别是移动某种全局文件或进行权限改变时。一个简单的测试可以获知是否运行在根目录下。下面脚本中变量DIRECTORY使用当前目录的命令替换操作,然后此变量值与” / “字符串比较( /为根目录)。如果变量值与字符串不等,则用户退出脚本,退出状态为1意味错误信息产生。
[root@localhost ~]# cat ifpwd.sh
#!/bin/sh
# ifpwd.sh
DIRECTORY=`pwd`
# grab the current dirctory
if [ "$DIRECTORY" != "/" ]; then
               # is it the root directory ?
               # no, the direct output to standard error, which is the screen
               # by default.
               echo "You need to be in the root directory no $DIRECTORY to run
               this script" >&2
               # exit with a value of 1, an error
               exit 1
fi
[root@localhost ~]# ./ifpwd.sh
You need to be in the root directory no /root to run
               this script

5、文件权限测试

可以用i f语句测试文件权限,下面简单测试文件test.txt是否被设置到变量LOGNAME,测试test.txt文件是否具有写的权限。下面的脚本先建立一个test.txt的空白文档,列出它的相关权限。然后执行脚本测试其是否可以写入,然后显示相关信息。
[root@localhost ~]# touch test.txt
[root@localhost ~]# ls -l test.txt
-rw-r--r-- 1 root root 0 Nov 21 15:21 test.txt
[root@localhost ~]# chmod u+x ifwr.sh
[root@localhost ~]# cat ifwr.sh
#!/bin/sh
# ifwr.sh
LOGFILE=test.txt
echo $LOGFILE
if [ ! -w "$LOGFILE" ]; then
               echo " You cannot write to $LOGFILE" >&2
else
               echo " You can write to $LOGFILE" >&2
fi
[root@localhost ~]# ./ifwr.sh
test.txt
You can write to test.txt

6、测试传递到脚本中的参数

if语句可用来测试传入脚本中参数的个数。使用特定变量$#,表示调用参数的个数。可以测试所需参数个数与调用参数个数是否相等。以下测试确保脚本有三个参数。如果没有,则返回一个可用信息到标准错误,然后代码退出并显示退出状态。如果参数数目等于3,则显示所有参数。
 [root@localhost ~]# cat ifparam.sh
#!/bin/sh
# ifparam
if [ $# -lt 3 ]; then
               # less than 3 parameters called, echo a usage message and exit
               # 如果少于三个参数则显示使用的信息,然后退出。
               echo "Usage: `basename $0`arg1 arg2 arg3" >&2
               exit 1
fi
# good, received 3 params, let's echo them
# 好,现在接受了三个参数,让我们开始显示他们
echo "arg1: $1"
echo "arg2: $2"
echo "arg3: $3"
[root@localhost ~]# ./ifparam.sh cup medal
Usage: ifparam.sharg1 arg2 arg3
[root@localhost ~]# ./ifparam.sh cup medal trophy
arg1: cup
arg2: medal
arg3: trophy
从上面的运行信息可以看出,如果只传入两个参数,则显示一可用信息,然后脚本退出。只有正确传入了三个参数了,才显示所有的参数然后退出。

7、决定脚本是否为交互模式

有时需要知道脚本运行是交互模式(终端模式)还是非交互模式(cron或at)。脚本也许需要这个信息以决定从哪里取得输入以及输出到哪里,使用test命令并带有-t选项很容易确认这一点。如果test返回值为1,则为交互模式。假如我是在一个终端下运行下面这个脚本。
[root@localhost ~]# cat ifinteractive.sh
#!/bin/sh
# ifinteractive.sh
if [ -t ]; then
               echo "We are interactive with a terminal"
else
               echo "We must be running from some background process probably
               cron or at"
fi
[root@localhost ~]# ./ifinteractive.sh
We are interactive with a terminal

8、变量设置测试

下面的例子测试环境变量EDITOR是否已设置。如果EDITOR变量为空,将此信息通知用户。如果已设置,在屏幕上显示编辑类型。
 [root@localhost ~]# cat ifeditor.sh
#!/bin/sh
# ifeditor.sh
if [ -z $EDITOR ]; then
               # the variable has not been set
               # 变量没有设置
               echo "Your EDITOR environment is not set"
else
               # let's see what it is
               # 如果设置了,让我们来看看它到底是什么
               echo "Using $EDITOR as the default editor"
fi
[root@localhost ~]# ./ifeditor.sh
Your EDITOR environment is not set

9、将脚本参数传入系统命令

可以向脚本传递位置参数,然后测试变量。这里,如果用户在脚本名字后键入目录名,脚本将重设$1特殊变量为一更有意义的名字。即DIRECTORY。这里需测试目录是否为空,如果目录为空,ls -A将返回空,然后对此返回一信息。
# ifdirec.sh
# assigning $1 to DIRECTORY variable
DIRECTORY=$1
if [ "`ls -A $DIRECTORY`" == "" ]; then
       # if it's an empty string, then it's empty
       echo "$DIRECTORY is indeed empty"
else    
       # otherwise it is not
       echo "$DIRECTORY is not empty"
fi
也可以使用下面的脚本替代上面的例子并产生同样的结果
[root@localhost ~]# cat ifdirec2.sh
#!/bin/sh
# ifdirec2
DIRECTORY=$1
if [ -z "`ls -A $DIRECTORY`" ]
then
               echo "$DIRECTORY is indeed empty"
else
               echo "$DIRECTORY is not empty"
fi

10、null命令用法

到目前为止,条件测试已经讲完了then和else部分,有时也许使用者并不关心条件为真或为假。不幸的是if语句各部分不能为空—一些语句已经可以这样做。为解决此问题, shell提供了:空命令。空命令永远为真(也正是预想的那样)。回到前面的例子,如果目录为空,可以只在then部分加入命令。
[root@localhost ~]# cat ifdirectory.sh
#!/bin/sh
# ifdirectory.sh
DIRECTORY=$1
if [ "`ls -A $DIRECTORY`" == "" ]
then
               echo "$DIRECTORY is indeed empty"
else :
               # do nothing
fi
[root@localhost ~]# ./ifdirectory.sh testd
testd is indeed empty
 

Shell脚本大量示例的更多相关文章

  1. 一个简单的linux下设置定时执行shell脚本的示例

    很多时候我们有希望服务器定时去运行一个脚本来触发一个操作,比如说定时去备份服务器数据.数据库数据等 不适合人工经常做的一些操作这里简单说下 shell Shell俗称壳,类似于DOS下的command ...

  2. shell脚本结构示例1

    2013年以来自己因为偷懒,少写了很多东西,今年计划把以前积累的总结出来. 先从shell开始写起吧. 干了快3年游戏运维,期间经常会写一些shell本,不少脚本其实有很多可以复用的部分. 按照自己的 ...

  3. Linux系统——shell脚本应用示例

    传入一个网段地址,自动找出本网段内存活的IP地址.2,将存活的IP地址当作密码来创建Linux用户,用户名格式为:你的名字_数字 3,有几个存活IP地址,就自动创建几个用户   4,最后将创建的用户名 ...

  4. shell脚本小示例

    求1-100自然数的和: 法一:for循环 #!/bin/bash # declare -i sum=0 for ((i=0;i<=100;i++));do let sum+=$i done e ...

  5. shell脚本调试

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-shell-debug/ 一. 前言 shell编程在unix/linux世界中使用得非常广泛,熟 ...

  6. 【转】Linux Shell脚本调试技术

    本文转载自:https://www.ibm.com/developerworks/cn/linux/l-cn-shell-debug/ Shell脚本调试技术 本文全面系统地介绍了shell脚本调试技 ...

  7. shell脚本调试技术_转

    转自:http://itlab.idcquan.com/linux/SHELL/727128.html 参考:https://linux.cn/article-8045-1.html 本文全面系统地介 ...

  8. 【转】shell脚本调试(bash trap support bashdb )

    原文网址:http://zhu8337797.blog.163.com/blog/static/170617549201122512712136/ 命 令 选 项 功 能 bash –x 脚本名 回显 ...

  9. Shell脚本调试技术

    http://www.ibm.com/developerworks/cn/linux/l-cn-shell-debug/ 一. 前言 shell编程在unix/linux世界中使用得非常广泛,熟练掌握 ...

随机推荐

  1. CentOS7 nginx+tomcat实现代理访问java web项目让项目支持jsp和php

    如果安装了Tomcat查看版本方法如下:注意:先进到tomcat的bin目录下(cd /tomcat目录/bin),在执行./version.sh [root@izbp bin]# ./version ...

  2. Selenium Page object Pattern usage

    使用Selenium的framework,大家免不了要使用他的page object pattern来开发适合自己的framework,原因很简单,page object 可以将测试的对象抽象成一个个 ...

  3. mysql Substr与char_length函数的应用

    update lee set name = SUBSTR(name, CHAR_LENGTH('lee')+1) where name like "lee%" char_lengt ...

  4. Zuul Timeouts

    19.13 Zuul Timeouts 19.13.1 Service Discovery Configuration If Zuul is using service discovery there ...

  5. IntelliJ IDEA遇到Unable to parse template “Class”错误

    在新安装的Ubuntu16下运行IntelliJ IDEA时, 遇到一个错误,在新建class的时候,提示Unable to parse template “Class” 通过查看 Settings ...

  6. uitableview分组的数据2中方式

    // // ViewController.m // tableviegroup // // Created by ganchaobo on 13-7-2. // Copyright (c) 2013年 ...

  7. FireFox 浏览器插件/扩展开发学习

    2014-11-08 内容存档在evernote,笔记名"FireFox 浏览器插件/扩展开发学习"

  8. Windbg使用方法

    hgy413的专栏 http://blog.csdn.net/hgy413/article/category/1143065

  9. HDU 3584 Cube (三维数状数组)

    Cube Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submi ...

  10. Magento模块升级修改数据库表结构

    Magento支持在模块中创建.删除.更新数据库表及字段.通过该方式,在插件开发的过程中,添加和修改字段变成了一件非常轻松的事情.只需要修改模块的版本号,同时在文件中添加一个符合命名规则的脚本就可以了 ...