Chinaunix首页 | 论坛 | 博客
  • 博客访问: 94775
  • 博文数量: 67
  • 博客积分: 30
  • 博客等级: 民兵
  • 技术积分: 330
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-11 15:34
文章分类
文章存档

2015年(1)

2014年(6)

2013年(10)

2012年(50)

我的朋友

分类:

2012-06-04 09:21:57

 shell是计算机科学中的名词,Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器)。它类似于DOS下的command.com。它接收用户命令,然后调用相应的应用程序。同时它又是一种程序设计语言。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高阶语言中才具有的控制结构,包括循环和分支。 近日看到这么全面的shell编程参考范例对于学习Linux的人而言,这是必须值得珍藏一份经典笔记。废话少说言归正传:
在书写正确脚本前,大概讲一下退出状态。任何命令进行时都将返回一个退出状态。如
果要观察其退出状态,使用最后状态命令:
$ echo $?
主要有4种退出状态。前面已经讲到了两种,即最后命令退出状态$ ?和控制次序命令( $ $、
| |)。其余两种是处理s h e l l脚本或s h e l l退出及相应退出状态或函数返回码。要退出当前进程,SHELL提供命令EXIT,一般格式为:
exit n
其中,n为一数字。
如果只在命令提示符下键入e x i t,假定没有在当前状态创建另一个s h e l l,将退出当前s h e l l。
如果在脚本中键入e x i t,s h e l l将试图(通常是这样)返回上一个命令返回值。有许多退出脚本
值,但其中相对于脚本和一般系统命令最重要的有两种,即:
退出状态0 退出成功,无错误。
退出状态1 退出失败,某处有错误。
可以在s h e l l脚本中加入自己的退出状态(它将退出脚本)。本书鼓励这样做,因为另一个
s h e l l脚本或返回函数可能要从s h e l l脚本中抽取退出脚本。另外,相信加入脚本本身的退出脚
本值是一种好的编程习惯。
如果愿意,用户可以在一个用户输入错误后或一个不可覆盖错误后或正常地处理结束后
退出脚本。
注意从现在起,本书所有脚本都将加入注释行。注释行将解释脚本具体含义,帮助用户
理解脚本。可以在任何地方加入注释行,因为其本身被解释器忽略。注释行应以#开头。

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

  2. # make a directory

  3. mkdir /home/dave/mydocs

  4. # copy all doc files

  5. cp *.docs /home/dave/docs

  6. # delete all doc files

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


流控制
i f、t h e n、e l s e语句提供条件测试。测试可以基于各种条件。例如文件的权限、长度、数
值或字符串的比较。这些测试返回值或者为真( 0),或者为假( 1)。基于此结果,可以进行
相关操作。在讲到条件测试时已经涉及了一些测试语法。
c a s e语句允许匹配模式、单词或值。一旦模式或值匹配,就可以基于这个匹配条件作其他
声明。


循环
循环或跳转是一系列命令的重复执行过程,本书提到了3种循环语句:
for 循环每次处理依次列表内信息,直至循环耗尽。
Until 循环此循环语句不常使用, u n t i l循环直至条件为真。条件部分在循环末尾部分。
While 循环w h i l e循环当条件为真时,循环执行,条件部分在循环头。
流控制语句的任何循环均可嵌套使用,例如可以在一个f o r循环中嵌入另一个f o r循环。
现在开始讲解循环和控制流,并举一些脚本实例。
从现在起,脚本中e c h o语句使用L I N U X或B S D版本,也就是说使用e c h o方法echo -e -n,
意即从e c h o结尾中下一行执行命令。应用于U N I X(系统V和B S D)的统一的e c h o命令参阅1 9
章s h e l l函数。

======================================GNU/LinuxFreeBSD======================================================

if then else语句
i f语句测试条件,测试条件返回真( 0)或假(1)后,可相应执行一系列语句。i f语句结
构对错误检查非常有用。其格式为:
if 条件1
then 命令1
elif 条件2
then 命令2
else 命令3
f i
让我们来具体讲解i f语句的各部分功能。
If 条件1 如果条件1为真
Then 那么
命令1 执行命令1
elif 条件2 如果条件1不成立
then 那么
命令2 执行命令2
else 如果条件1,2均不成立
命令3 那么执行命令3
fi 完成
i f语句必须以单词f i终止。在i f语句中漏写f i是最一般的错误。我自己有时也是这样。
e l i f和e l s e为可选项,如果语句中没有否则部分,那么就不需要e l i f和e l s e部分。I f语句可以
有许多e l i f部分。最常用的i f语句是if then fi结构。

if...then是最常见的条件判断语句,简而言之,就是符合某个条件判断的时候,就予以进行某项工作就是了,我们可以简单地这样子看:
if [ 条件判断表达式 ]; then
            当条件判断表达式成立时可以执行的命令
fi

 

较特别的是,如果有多个条件判断时,可以将多个判断写入一个中括号,还可以使用多个中括号隔开,而括号和括号之间,则以&&或||来隔开,这个要和命令行中的&&,||区别开来。


下面看一些例子。

 

  1. # cat iftest

  2. #!/bin/sh

  3. # iftest

  4. # this is a comment line, all commment lines start with a #

  5. if [ "10" -lt "12" ]

  6. then

  7.         # yes 10 is less than 12

  8.         echo "Yes, 10 is less than 12"

  9. fi

变量值测试
通过测试设置为接受用户输入的变量可以测知用户是否输入信息。下面的例子中测试用户键入
r e t u r n键后变量n a m e是否包含任何信息。

 

  1. # cat iftest2.sh

  2. #!/bin/sh

  3. # iftest2

  4. echo -n "Enter your name :"

  5. read NAME

  6. # did the user just hit return ???

  7. if [ "$NAME" == "" ]; then

  8.         echo "You did not enter any information"

  9. fi



  10. #./iftest2.sh

  11. Enter your name :

  12. You did not enter any information

 

=====================================GNU/LinuxFreeBSD==================================


grep输出检查
不必拘泥于变量或数值测试,也可以测知系统命令是否成功返回。对g r e p使用i f语句找出
g r e p是否成功返回信息。下面的例子中g r e p用于查看D a v e是否在数据文件d a t a . f i l e中,注意
‘D a v e \ >’用于精确匹配。
  1. [root@localhost ~]# cat grepif.sh

  2. #!/bin/sh

  3. # grepif.sh

  4. if grep 'Dave\>' data.file > /dev/null 2>&1

  5. then

  6.                 echo "Great Dave is in the file"

  7. else

  8.                 echo "No Dave is not in the file"

  9. fi

  10. [root@localhost ~]# ./grepif.sh

  11. No Dave is not in the file
 
用变量测试grep输出
正像前面看到的,可以用g r e p作字符串操作。下面的脚本中,用户输入一个名字列表,
g r e p在变量中查找,要求其包含人名P e t e r。
下面是具体的代码情况和运行信息。
  1. [root@localhost ~]# cat grepstr.sh

  2. #!/bin/sh

  3. # grepstr

  4. echo -n "Enter a list of names:"

  5. read list

  6. if echo $list | grep "Peter" > /dev/null 2>&1

  7. then

  8.                 echo "Peter is here"

  9.                 # could do some processing here...

  10. else

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

  12. fi

  13. [root@localhost ~]# ./grepstr.sh

  14. Enter a list of names:John Louise Peter James

  15. Peter is here
 
文件拷贝输出检查
下面测试文件拷贝是否正常,如果c p命令并没有拷贝文件m y f i l e到m y f i l e . b a k,则打印错
误信息。注意错误信息中` basename $0`打印脚本名。
如果脚本错误退出,一个好习惯是显示脚本名并将之定向到标准错误中。用户应该知道
产生错误的脚本名。
  1. [root@localhost ~]# cat ifcp.sh

  2. #!/bin/sh

  3. # ifcp.sh

  4. if cp myfile myfile.bak; then

  5.                 echo "good copy"

  6. else

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

  8. fi

  9. [root@localhost ~]# ./ifcp.sh

  10. cp: cannot stat `myfile': No such file or directory

  11. ifcp.sh: error could not copy the file

 

注意,文件可能没找到,系统也产生本身的错误信息,这类错误信息可能与输出混在一
起。既然已经显示系统错误信息获知脚本失败,就没必要显示两次。要去除系统产生的错误
和系统输出,只需简单的将标准错误和输出重定向即可。修改脚本为: >/dev/null 2>&1。

 

 

  1. [root@localhost ~]# cat ifcp.sh

  2. #!/bin/sh

  3. # ifcp.sh

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

  5.                 echo "good copy"

  6. else

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

  8. fi

  9. [root@localhost ~]# ./ifcp.sh

  10. ifcp.sh: error could not copy the file

 

上面当中>/dev/null表示任何标准输出都定向到那个无尽的“黑洞”/de/null中,然后2>&1表示
错误输出也是到/dev/null中,&1表示前面的那个/dev/null,脚本运行时,所有输出包括错误重定向至系统垃圾堆。

当前目录测试
当运行一些管理脚本时,可能要在根目录下运行它,特别是移动某种全局文件或进行权
限改变时。一个简单的测试可以获知是否运行在根目录下。下面脚本中变量D I R E C TO RY使用
当前目录的命令替换操作,然后此变量值与" / "字符串比较( /为根目录)。如果变量值与字符
串不等,则用户退出脚本,退出状态为1意味错误信息产生。

 

 

  1. [root@localhost ~]# cat ifpwd.sh

  2. #!/bin/sh

  3. # ifpwd.sh

  4. DIRECTORY=`pwd`

  5. # grab the current dirctory

  6. if [ "$DIRECTORY" != "/" ]; then

  7.                 # is it the root directory ?

  8.                 # no, the direct output to standard error, which is the screen

  9.                 # by default.

  10.                 echo "You need to be in the root directory no $DIRECTORY to run

  11.                 this script" >&2

  12.                 # exit with a value of 1, an error

  13.                 exit 1

  14. fi

  15. [root@localhost ~]# ./ifpwd.sh

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

  17.                 this script

 

文件权限测试
可以用i f语句测试文件权限,下面简单测试文件t e s t . t x t是否被设置到变量L O G N A M E,测试test.txt文件是否具有写的权限。下面的脚本先建立一个test.txt的空白文档,列出它的相关权限。然后执行脚本测试其是否可以写入,然后显示相关信息。

 

 

  1. [root@localhost ~]# touch test.txt

  2. [root@localhost ~]# ls -l test.txt

  3. -rw-r--r-- 1 root root 0 Nov 21 15:21 test.txt

  4. [root@localhost ~]# chmod u+x ifwr.sh

  5. [root@localhost ~]# cat ifwr.sh

  6. #!/bin/sh

  7. # ifwr.sh

  8. LOGFILE=test.txt

  9. echo $LOGFILE

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

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

  12. else

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

  14. fi

  15. [root@localhost ~]# ./ifwr.sh

  16. test.txt

  17. You can write to test.txt

 

测试传递到脚本中的参数
i f语句可用来测试传入脚本中参数的个数。使用特定变量$ #,表示调用参数的个数。可以
测试所需参数个数与调用参数个数是否相等。
以下测试确保脚本有三个参数。如果没有,则返回一个可用信息到标准错误,然后代码
退出并显示退出状态。如果参数数目等于3,则显示所有参数。

 

  1. [root@localhost ~]# cat ifparam.sh

  2. #!/bin/sh

  3. # ifparam

  4. if [ $# -lt 3 ]; then

  5.                 # less than 3 parameters called, echo a usage message and exit

  6.                 # 如果少于三个参数则显示使用的信息,然后退出。

  7.                 echo "Usage: `basename $0`arg1 arg2 arg3" >&2

  8.                 exit 1

  9. fi

  10. # good, received 3 params, let's echo them

  11. # 好,现在接受了三个参数,让我们开始显示他们

  12. echo "arg1: $1"

  13. echo "arg2: $2"

  14. echo "arg3: $3"

  15. [root@localhost ~]# ./ifparam.sh cup medal

  16. Usage: ifparam.sharg1 arg2 arg3

  17. [root@localhost ~]# ./ifparam.sh cup medal trophy

  18. arg1: cup

  19. arg2: medal

  20. arg3: trophy

 

从上面的运行信息可以看出,如果只传入两个参数,则显示一可用信息,然后脚本退出。
只有正确传入了三个参数了,才显示所有的参数然后退出。

决定脚本是否为交互模式
有时需要知道脚本运行是交互模式(终端模式)还是非交互模式( c r o n或a t)。脚本也许
需要这个信息以决定从哪里取得输入以及输出到哪里,使用t e s t命令并带有- t选项很容易确认
这一点。如果t e s t返回值为1,则为交互模式。假如我是在一个终端下运行下面这个脚本。

 

 

  1. [root@localhost ~]# cat ifinteractive.sh

  2. #!/bin/sh

  3. # ifinteractive.sh

  4. if [ -t ]; then

  5.                 echo "We are interactive with a terminal"

  6. else

  7.                 echo "We must be running from some background process probably

  8.                 cron or at"

  9. fi

  10. [root@localhost ~]# ./ifinteractive.sh

  11. We are interactive with a terminal

 

简单的if else语句
下一个i f语句有可能是使用最广泛的:
if 条件
t h e n
命令1
e l s e
命令2
f i
使用i f语句的e l s e部分可在条件测试为假时采取适当动作。

变量设置测试
下面的例子测试环境变量E D I TO R是否已设置。如果E D I TO R变量为空,将此信息通知用
户。如果已设置,在屏幕上显示编辑类型。

 

  1. [root@localhost ~]# cat ifeditor.sh

  2. #!/bin/sh

  3. # ifeditor.sh

  4. if [ -z $EDITOR ]; then

  5.                 # the variable has not been set

  6.                 # 变量没有设置

  7.                 echo "Your EDITOR environment is not set"

  8. else

  9.                 # let's see what it is

  10.                 # 如果设置了,让我们来看看它到底是什么

  11.                 echo "Using $EDITOR as the default editor"

  12. fi

  13. [root@localhost ~]# ./ifeditor.sh

  14. Your EDITOR environment is not set

=====================================GNU/LinuxFreeBSD==================================

这些东西很是有用,暂时先到这里这些还得慢慢品;改日继续。希望这份转载的笔记对我对大家都带来

帮助让大家更容易理解和书写shell脚本;后面的内容会更加精彩同时也会展现出shell更强大的功能。

阅读(447) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~