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、循环和流控制

2、循环

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


二、实例讲解

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

从现在起,脚本中语句使用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
thenecho "Great Dave is in the file"
elseecho "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
thenecho "Peter is here"# could do some processing here...
elseecho "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; thenecho "good copy"
elseecho "`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; thenecho "good copy"
elseecho "`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 runthis script" >&2# exit with a value of 1, an errorexit 1
fi
[root@localhost ~]# ./ifpwd.sh
You need to be in the root directory no /root to runthis 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" ]; thenecho " You cannot write to $LOGFILE" >&2
elseecho " 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" >&2exit 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 ]; thenecho "We are interactive with a terminal"
elseecho "We must be running from some background process probablycron or at"
fi
[root@localhost ~]# ./ifinteractive.sh
We are interactive with a terminal

8、变量设置测试

下面的例子测试环境变量EDITOR是否已设置。如果EDITOR变量为空,将此信息通知用户。如果已设置,在屏幕上显示编辑类型。
 [root@localhost ~]# cat ifeditor.sh #!/bin/sh# ifeditor.shif [ -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 emptyecho "$DIRECTORY is indeed empty"
else    # otherwise it is notecho "$DIRECTORY is not empty"
fi
也可以使用下面的脚本替代上面的例子并产生同样的结果
[root@localhost ~]# cat ifdirec2.sh
#!/bin/sh
# ifdirec2
DIRECTORY=$1
if [ -z "`ls -A $DIRECTORY`" ]
thenecho "$DIRECTORY is indeed empty"
elseecho "$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`" == "" ]
thenecho "$DIRECTORY is indeed empty"
else :# do nothing
fi
[root@localhost ~]# ./ifdirectory.sh testd
testd is indeed empty

Shell脚本大量示例相关推荐

  1. 运维linux脚本实例,Shell脚本使用示例

    目录如下: 1.编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小. 2.编写脚本/root ...

  2. linux 备份文件脚本,linux 下shell脚本备份文件(示例代码)

    以下是shell自动备份用的: 主要功能: 1)将pathSrc目录中的文件拷贝到pathDst目录中去. 具体步骤:先查询源目录和目标目录中的文件,分别存在fileSrc和fileDst中. -&g ...

  3. shell脚本调试技术

    Shell脚本调试技术 曹 羽中 (caoyuz@cn.ibm.com), 软件工程师, IBM中国开发中心 曹羽中,在北京航空航天大学获得计算机软件与理论专业的硕士学位,具有数年的 unix 环境下 ...

  4. shell脚本——调试(-n / -x /-c)

    我们在前面介绍的调试手段是通过修改shell脚本的源代码,从其输出相关的调试信息来定位错误的,那有没有不修改源代码来调试shell脚本的方法呢?有的,那就是使用shell的执行选项,下面将介绍一些常用 ...

  5. linux脚本里调执行命令,使用shell的-n/-x/-x执行选项调试Shell脚本

    我们在前面介绍的调试手段是通过修改shell脚本的源代码,从其输出相关的调试信息来定位错误的,那有没有不修改源代码来调试shell脚本的方法呢?有的,那就是使用shell的执行选项,下面将介绍一些常用 ...

  6. getopt设计shell脚本选项

    写shell脚本的时候,通过while.case.shift来设计脚本的命令行选项是一件比较麻烦的事,因为Unix命令行的选项和参数自由度很高,支持短选项和长选项,参数可能是可选的,选项顺序可能是无所 ...

  7. Azkaban实战,Command类型单一job示例,任务中执行外部shell脚本,Command类型多job工作flow,HDFS操作任务,MapReduce任务,HIVE任务

    1.Azkaban实战 Azkaba内置的任务类型支持command.java Command类型单一job示例 1.创建job描述文件 vi command.job #command.job typ ...

  8. 在Shell脚本中声明和使用布尔变量示例

    需要定义一个名为failed的bash变量,并将值设置为False.当从cron作业调用我们的脚本时,特定的任务可能会失败,然后我需要将failed转换为True.基于$failed,我需要发送一封电 ...

  9. Linux教程 - 在Shell脚本中声明和使用布尔变量示例

    需要定义一个名为failed的bash变量,并将值设置为False.当从cron作业调用我们的脚本时,特定的任务可能会失败,然后我需要将failed转换为True.基于$failed,我需要发送一封电 ...

最新文章

  1. AngularJS 使用$sce控制代码安全检查
  2. Cors 跨域Access-Control-Allow-Origin
  3. 树莓派GPIO的两种模式区别
  4. 随机发牌_用Python制作4人扑克牌发牌游戏
  5. VS2010附加进程调试DLL时断点无法断下的解决方法
  6. STM32工作笔记045---SystemInit时钟系统初始化函数剖析
  7. asp.net mvc 实现上传文件带进度条
  8. Codeproject收藏
  9. 北斗sdk_北斗定位终端开发技术方案.pdf
  10. IDEA更改编码颜色/主题
  11. LTE-PCC SCC
  12. 此windows副本不是正版_阳光单职业传奇正版-阳光单职业传奇正版官网版v2.0
  13. windows下安装you-get的简要记录
  14. 京东联盟API - 万能转链接口 - 高效转链接口 - 接口定制
  15. Codeforces #467 (Div. 2) B. Vile Grasshoppers 蚂蚱的题目
  16. TransMac 下载 win7 win10 U盘启动的制作方法 win7 win10 U盘启动的 transMac制作方法
  17. 北京外国语大学本科毕业论文答辩和论文选题PPT模板
  18. 高效学习的 36 种思维
  19. 华为“废太子”李一男 出狱后能否东山再起?
  20. 《RocketMQ技术内幕:RocketMQ架构设计与实现原理》一导读...

热门文章

  1. 安装mysql出现错误_安装Mysql时出现错误及解决办法
  2. 数据结构实验之栈与队列一:进制转换
  3. 工作流引擎Activiti使用总结
  4. Git++ - 有趣的命令
  5. Java Servlet 技术简介
  6. WebAssembly 系列(一):生动形象地介绍 WebAssembly
  7. ROS探索总结(十)(十一)(十二)——语音控制 机器视觉 坐标系统
  8. OpenCV2.4.4中调用SIFT特征检测器进行图像匹配
  9. 分类器评价与在R中的实现:收益图与提升图
  10. 【OpenCV3】双线性插值