2023年11月27日发(作者:)

Shell脚本⼤量⽰例

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循环直⾄条件为真。条件部分在循环末尾部分。

不必拘泥于变量或数值测试,也可以测知系统命令是否成功返回。对grep使⽤if语句找出,grep是否成功返回信息。下⾯的例

⼦中grep⽤于查看Dave是否在数据⽂件中,注意’Dave>‘⽤于精确匹配。

[root@localhost ~]# cat

#!/bin/sh

#

if grep 'Dave>' > /dev/null 2>&1

then

echo "Great Dave is in the file"

else

echo "No Dave is not in the file"

fi

[root@localhost ~]# ./

No Dave is not in the file

2、⽤变量测试grep输出

正像前⾯看到的,可以⽤grep作字符串操作。下⾯的脚本中,⽤户输⼊⼀个名字列表,grep在变量中查找,要求其包含⼈名

Peter

[root@localhost ~]# cat

#!/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

else

echo "Peter's not in the list. No comment!"

fi

[root@localhost ~]# ./

Enter a list of names:John Louise Peter James

Peter is here

3、⽂件拷贝输出检查

下⾯测试⽂件拷贝是否正常,如果cp命令并没有拷贝⽂件myfile,则打印错误信息。注意错误信息中basename

注意,⽂件可能没找到,系统也产⽣本⾝的错误信息,这类错误信息可能与输出混在⼀起。既然已经显⽰系统错误信息获知脚

本失败,就没必要显⽰两次。要去除系统产⽣的错误和系统输出,只需简单的将标准错误和输出重定向即可。修改脚本为:

>/dev/null 2>&1

[root@localhost ~]# cat

#!/bin/sh

#

if cp myfile > /dev/null 2>&1; then

echo "good copy"

else

echo "`basename $0`: error could not copy the file" >&2

fi

[root@localhost ~]# ./

: error could not copy the file

上⾯当中>/dev/null表⽰任何标准输出都定向到那个⽆尽的⿊洞”/de/null中,然后2>&1表⽰错误输出也是到/dev/null中,&1

⽰前⾯的那个/dev/null,脚本运⾏时,所有输出包括错误重定向⾄系统垃圾堆。

4、当前⽬录测试

当运⾏⼀些管理脚本时,可能要在根⽬录下运⾏它,特别是移动某种全局⽂件或进⾏权限改变时。⼀个简单的测试可以获知是

否运⾏在根⽬录下。下⾯脚本中变量DIRECTORY使⽤当前⽬录的命令替换操作,然后此变量值与” / “字符串⽐较( /为根⽬

录)。如果变量值与字符串不等,则⽤户退出脚本,退出状态为1意味错误信息产⽣。

[root@localhost ~]# cat

#!/bin/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 ~]# ./

You need to be in the root directory no /root to run

this script

5、⽂件权限测试

可以⽤i f语句测试⽂件权限,下⾯简单测试⽂件是否被设置到变量LOGNAME,测试⽂件是否具有写的权限。下

[root@localhost ~]# touch

[root@localhost ~]# ls -l

-rw-r--r-- 1 root root 0 Nov 21 15:21

[root@localhost ~]# chmod u+x

[root@localhost ~]# cat

#!/bin/sh

#

LOGFILE=

echo $LOGFILE

if [ ! -w "$LOGFILE" ]; then

echo " You cannot write to $LOGFILE" >&2

else

echo " You can write to $LOGFILE" >&2

fi

[root@localhost ~]# ./

You can write to

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

if语句可⽤来测试传⼊脚本中参数的个数。使⽤特定变量$#,表⽰调⽤参数的个数。可以测试所需参数个数与调⽤参数个数是

否相等。以下测试确保脚本有三个参数。如果没有,则返回⼀个可⽤信息到标准错误,然后代码退出并显⽰退出状态。如果参

数数⽬等于3,则显⽰所有参数。

[root@localhost ~]# cat

#!/bin/sh

# ifparam

[root@localhost ~]# cat

#!/bin/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 ~]# ./

We are interactive with a terminal

8、变量设置测试

下⾯的例⼦测试环境变量EDITOR是否已设置。如果EDITOR变量为空,将此信息通知⽤户。如果已设置,在屏幕上显⽰编辑类

型。

[root@localhost ~]# cat

#!/bin/sh

# ifdirec2

DIRECTORY=$1

if [ -z "`ls -A $DIRECTORY`" ]

then

echo "$DIRECTORY is indeed empty"

else

echo "$DIRECTORY is not empty"

fi

10null命令⽤法

到⽬前为⽌,条件测试已经讲完了thenelse部分,有时也许使⽤者并不关⼼条件为真或为假。不幸的是if语句各部分不能为

⼀些语句已经可以这样做。为解决此问题, shell提供了:空命令提供了:空命令。空命令永远为真(也正是预想的那样)。回到前⾯的例。空命令永远为真(也正是预想的那样)。回到前⾯的例

⼦,如果⽬录为空,可以只在then部分加⼊命令。

[root@localhost ~]# cat

#!/bin/sh

#

DIRECTORY=$1

if [ "`ls -A $DIRECTORY`" == "" ]

then

echo "$DIRECTORY is indeed empty"