<来源网址:http://yuxin.blog.51cto.com/addblog.php>

 Linux中的shell脚本编程:

 

shell脚本是什么:

shell脚本是一个可反复执行的能够实现一些功能的文件,一般以.sh结尾。

Shell脚本有什么用:

在工作中你可能需要经常执行一组命令以完成一些任务,如果每天都要这么做就会变得枯燥无趣,或者这组命令需要在多台服务器上执行,而其中又需要大量的修改某些配置文件,如果每次都手动的去执行这些命令就会极大的降低工作效率而且很容易因为粗心某个单词写错造成排错上的困难,这时候就可以写个shell脚本来完成以上工作,需要的时候执行一次就可以了,还可以把它写到任务计划里边,让它周期性的自动执行,即提高了工作效率也降低了出错几率。

Shell脚本的结构组成和执行顺序:

在shell脚本中第一行是有特殊意义的,用来标示执行脚本的shell程序,例如:

#!/bin/bash : 这表示该脚本使用/bin/bash来执行,脚本可以由哪些shell程序来执行取决于你当前的系统支持哪些shell,可以用 # cat /etc/shells来查看当前系统支持的shell。

脚本中的第二行一般为#号开头的注释行,用来描述脚本的作用和功能,当然如果你只是用来测试练习使用的也可以不写,但最好能养成一个好的习惯,在shell脚本中所有以#号开头的行都为注释行,用来描述脚本的作用和提示性信息,在脚本执行过程中是不会被执行的,但脚本开头的第一行的第一个#号除外,它是用来标示脚本的执行shell程序的。

脚本中以第三行开始就是脚本的主体组成也就是要执行一个个命令了,如果你第二行的注释信息有好多行,也可能就不是从第三行开始了,总之如果是不想让被执行的内容该行开头都要加上#号。

脚本的执行顺序,正常情况下读取脚本的第一行决定调用哪个shell程序来执行该脚本,然后开始自上而下、自左往右逐条执行每一行的每一个命令,如果一行里要执行多个命令需使用;号隔开,遇到#号则跳过该行,但是也有例外情况,脚本中的某些关键字可以改变脚本的执行顺序,甚至在中断该脚本的执行,例如,exit break while 等,下边会做详细介绍。

 

第一章、Shell脚本中的变量

 

有些时候在脚本的编写过程中你需要反复用到同一个路径或者同一段字符串,这时你就可以定义一个变量,把你反复用到的这段内容赋值给该变量,当用到的时候之需要调用该变量就可以了。变量的赋值不仅仅是固定的一段字符串,可以是一条命令的执行结果,可以是脚本互交输入的内容,也可以是与其他变量算术运算后的结果,按变量的类型可分为以下几类:

环境变量:对当前shell和子shell生效,像脚本的执行就是在子shell中进行,所以在当前shell中定义的环境变量同样可以在shell脚本中使用,可使用#env 命令查看当前shell中的所有环境变量,系统预定义的环境变量可直接调用。

环境变量的设置方法有三种:

1># declare -x VAR_NAME=value

2># export VAR_NAE=value

3># set VAR_NAME=value

VAR_NAME为变量名称该名称为自定义,但要遵循以下三个原则:

1.只能包含字母、数字和下划线,并且不能以数字开头

2.不能与关键字冲突 (例如if for case 等,下边会详细介绍)

3.最好能做到见名知意也就是起个有意义的名字

value为变量的具体内容

# echo $VAR_NAME 来显示变量的内容

局部变量:也叫本地变量与环境变量想对应,只对当前shell生效,shell脚本中定义的变量大部分都为这类变量,当脚本执行结束时定义的变量也随之消失。可使用# set 命令查看当前shell中的所有局部变量。

局部变量的设置方法一般为:VAR_NAME=value,同样名称的定义也要遵循上边提到的定义环境变量的三个原则。

特殊变量:shell对一些参数做特殊处理,这写参数只能被引用而不能被赋值,例如:

$? : 引用上条命令的执行结果的返回值

0 : 上条命令成功执行

1-255 :均为执行失败

$$ : 脚本运行的当前进程ID号

$# : 向脚本传递的参数个数

位置变量 :和特殊变量一样他们只能被引用不能被赋值,如果要向脚本传递参数就可以用位置变量来引用传递的参数,此数目可以任意多,但只有前9个可以被访问,例如:

$0 : 表示脚本名称

$1 : 表示向脚本传递的第一个参数

$2 : 表示向脚本传递的第二个参数

$3 …

.

.

$9 : 表示向脚本传递的第九个参数

变量引用:上面讲述了四种类型的变量,如何引用自己定义的变量呢其实很简单,环境变量和局部变量只需要在变量名前加$符号就可以了,例如:

# export COS=ubuntu //定义环境变量COS赋值为ubuntu

# echo $COS //使用echo 命令回显变量COS

ubuntu //变量的值

变量自身也可以引用其他变量,例如:

# VAR=”$COS is good.” //定义局部变量VAR赋值为$COS is good.

# echo $VAR //使用echo命令回显变量VAR

ubuntu is good. //变量VAR的值

上边例子可以看出变量VAR赋值时引用了变量COS的值,但要注意如果在给变量赋值时引用了其他变量需要用”“双引号把整个内容括起来,不然是不会做变量替换,如下:

# VAR='$COS is good.'

# echo $VAR

$COS is good.

可以看到$COS并没有做变量替换,还是显示为$COS

变量的赋值还可以引用其他命令的执行结果,例如:

# VAR=`pwd`

# echo $VAR

/root

上边这个例子中变量VAR的赋值引用了命令pwd的执行结果,同时也要注意如果引用的是命令的执行结果则需要把这个命令用``反引号括起来。

 

第二章、if条件判断语句

有些时候在shell脚本的执行过程中可能发生各种意外情况,例如,你想写个脚本来创建几个空目录,当脚本执行完毕时发现有些目录并不是空的,因为这个目录之前就已经存在了,而你再执行mkdir命令时并不能执行成功,或者你想让脚本执行成功或失败时能够echo一句话再结束脚本,而不是默不作声脚本万一没有执行成功也无法察觉,这时都需要用到if条件判断,if语句可分为单分支、双分支和多分支三个类型。

单分支if语法格式:

if 条件 ; then

命令1

命令2 …

fi

示例:

# vim test.sh

#!/bin/bash

# test if

if pwd ; then

echo It is good.

fi

该脚本的意思是:如果pwd命令执行成功则显示一句话It is good,如果不成功

则结束脚本,执行结果如下:

# bash test.sh

/root

It is good.

双分支if语法格式:

if 条件;then

命令...

else

命令...

fi

示例:

# vim test.sh

#!/bin/bash

# test if

if lss ; then

echo command success.

else

echo command failed.

fi

该脚本的意思是:如果lss这个命令执行成功则显示command success,否则显示command failed,执行结果如下:

# bash test.sh

test.sh: line 3: lss: command not found

command failed

可以看到因为lss命令执行失败,显示command failed,如果不想显示命令的执行结果只是用来做条件来判断是可以用 &> /dev/null 进行输出重定向。

多分支if语句语法格式:

if 条件一 ; then

命令...

elif 条件二 ; then

命令...

else

命令...

fi

示例:

# vim test.sh

#!/bin/bash

# test if

if lss &> /dev/null ; then

echo less success.

elif ls &> /dev/null ;then

echo ls success.

else

echo all error.

fi

该脚本的意思是:如果lss命令执行成功显示 lss success,如果lss命令没有执行成功则判断ls 命令执行是否完成,成功则显示ls success,否则显示 all error,执行结果如下:

# bash test.sh

ls success.

以上示例都是用命令执行是否成功来做条件的判断的,其实也可以用条件测试的结果的来判断,例如判断变量COS的值是否为空,或者是否与变量VAR的值是否相同等,条件测试后边会做详细介绍,另外if语句中也可以在嵌套if语句,进行二次判断,使用格式相同,从上边的例子也可以看出if语句只要满足任何一个条见就退出整个语句,不再进行其他条件的判断。

 

第三章、shell中的条件测试算术运算

 

shell中使用条件测试和算术运算可以使脚本更加智能,能够判断命令是否执行成功也可以用来测试两个变量的数值是否相等,也可以来判断两个字符串是否一致,条件测试大致可分为三类,其基本语法格式如下:

[ 条件 ] 或者 [[ 条件 ]]

整数测试:可使用的选项有:

-eq

等于

-gt

大于

-ge

不大于

-ne

不等于

-lt

小于

-le

不小于

 

示例:

# vim test.sh

#!/bin/bash

# test

COS=1

if [ $COS -eq 1 ] ;then

echo success.

else

echo failed.

fi

执行结果为:

# bash test.sh

success.

因为变量COS的值等于1,所以执行echo success.

字符串测试:可使用的选项有:

=

等于

>

大于

>=

大于等于

!=

不等于

<

小于

<=

小于等于

 

示例:

# vim test.sh

#!/bin/bash

# test

VAR=ubuntu

if [ $VAR = ubuntu ] ; then

echo good.

fi

脚本执行结果:

# bash test.sh

good.

如果变量中存在空格或单引号需要用双引号把他们括起来。

文件测试:可使用的选项有:

-e

测试文件是否存在

-s

是否存在并不为空

-f

是否是文件

-d

是否是目录

-r

是否有读权限

-w

是否有写权限

-x

是否有执行权限

-n t

那个文件更新

示例:

# vim test.sh

#!/bin/bash

# test

if [ -x /etc/passwd ] ;then

echo good.

else

echo bad.

fi

执行结果:

# bash test.sh

bad.

因为对/etc/passwd文件没有执行权限所以执行echo bad.。

算术运算:可用的选项有:

+

-

*

/

%

取余

 

 

 

语法格式:

$[运算表达式] 或者

$((运算表达式))

示例:

# VAR=$[2+3]

# echo $VAR

5

 

第四章、case条件判断语

 

当if条件判断语句做某写字符串测试时,需要编写大量陈长的语句来实现,例如,指定一个变量,如果变量的值为A则显示first line,如果变量的值为B则显示second line,如果变量值为C则显示third line,用if条件判断语句:

示例:

# vim test.sh

#!/bin/bash

# test

COS=B

if [ $COS = A ];then

echo first line

elif [ $COS = B ]; then

echo second line

elif [ $COS = C ]; then

echo third line

fi

执行结果:

# bash test.sh

second line

如果用case条件判断语句则可以大大简化需要编写的内容

case语法格式:

case 变量 in

字符串1)

命令... ;;

字符串2)

命令... ;;

字符串3)

命令... ;;

esac

示例:

# vim test.sh

#!/bin/bash

# test case

COS=B

case $COS in

A)

echo first line ;;

B)

echo second line ;;

C)

echo third line ;;

esac

执行结果:

# bash test.sh

second line

从以上对比可以看出,如果是字符串测试case语句要比if语句简化了很多,而且条理非常明晰。

 

第五章、for循环语句

 

循环顾名思义会循环执行直到满足一定条件退出循环,for循环为遍历列表循环,列表即可以是定义的一个数组也可以是一个命令的执行结果也可以是一个变量,for循环会逐个匹配列表中每个字符串,默认是以空格和换行符为分割点,所以如果你给出的列表中存在一个字符串包含有空格的话,for循环会把他拆开作为两个值。

For循环语法格式:

for 变量 in 列表;do

命令...

done

示例:

# vim test.sh

#!/bin/bash

# test for

for I in {1..5}; do

echo $I

done

该脚本的意思是:如果变量I在数组{1..5}中,执行显示变量I,第一次循环I=1,执行echo $I 也就是显示1,第二次循环I=2,执行echo $I 也就是显示2,以此类推...直到I=5时,遍历完数组中的所有数值,显示5,然后结束for循环,脚本执行结果如下:

# bash test.sh

1

2

3

4

5

for循环会以空格分隔列表中每个值,如果数据值中有空格,或者包含有单引号,则必须使用双引号括起来,例如:

# vim test.sh

#!/bin/bash

# test for

for I in a ab a b a'b' ;do

echo $I

done

执行结果为:

# bash test.sh

a

ab

a

b

ab

这并不是我们想要的结果,需要用下面的方法:

# vim test.sh

#!/bin/bash

# test for

for I in a ab “a b” “a'b'” ;do

echo $I

done

执行结果为:

# bash test.sh

a

ab

a b

a'b'

这才是我们想要的结果。

第六章、while、until循环语句、break和 continue

 

while循环语句可以让满足某条件的情况下反复执行while循环中的命令,当条件不满足时自动退出循环,继续按顺序执行脚本中的其他内容,其基本语法格式如下:

while循环语法格式:

while 条件 ; do

命令...

done

示例:

# vim test.sh

#!/bin/bash

# test while

declare -i COS=0

while [ $COS -lt 5 ] ; do

echo $COS

let COS++

done

脚本的意思是:定义整型变量COS并赋值为0,如果COS的值小于5,则显示COS的值并let COS++ 让COS的值自动加1,执行结果如下:

# bash test.sh

0

1

2

3

4

可见当COS的值变成5时不满足条件,则退出while循环,结束脚本。

break可以中断循环,和if语句配合使用,在while循环中满足if语句的条件时退出while循环,还用刚才的脚本来试试break的作用。

示例:

# vim test.sh

#!/bin/bash

# test break

declare -i COS=0

while [ $COS -lt 5 ];do

if [ $COS -eq 3 ]; then

break

fi

echo $COS

let COS++

done

与上边的例子不同的地方在于这次在循环中增加了if条件判断,如果COS的值等于3时执行break,看看什么效果:

# bash test.sh

0

1

2

当COS的值为3时执行了break退出了while循环。

continue可以提前中断这次循环,进入下一次循环,与break不同的地方在于break是直接退出循环,而continue是中断该次循环进入下一次循环,继续用刚才的例子看下和break有什么不同。

示例:

# vim test.sh

#!/bin/bash

# test continue

declare -i COS=0

while [ $COS -lt 5 ]; do

if [ $COS -eq 3 ]; then

let COS++

continue

fi

echo $COS

let COS++

done

执行结果:

# bash test.sh

0

1

2

4

由于COS=3时执行了continue,所以没有显示3,这就是continue的作用。

Until 循环是直到条件满足时才退出循环,与while循环正好相反,语法格式与while一样。

示例:

# vim test.sh

#!/bin/bash

# test until

declare -i COS=0

until [ $COS -eq 5 ] ;do

echo $COS

done

执行结果:

# bash test.sh

0

1

2

3

4

从脚本的执行结果可以看出,当until的条件也就是COS=5时,退出了循环。

 

第七章、函数

 

shell脚本中的函数与变量有点类似,都是可以定义一个名字等使用时直接调用就可以了,但是变量只能进行简单的字符串或者命令的赋值,而函数可以执行更复杂的命令,甚至可以说是脚本中的脚本,其基本语法格式如下:

函数语法格式:

function 名字 {

命令...

}

或者

名字() {

命令...

}

示例:

# vim test.sh

#!/bin/bash

# test function

FUN() {

COS=`date +%F`

echo “Today is $COS.”

}

echo Hello

FUN

执行结果:

# bash test.sh

Hello

Today is 2012-06-19.

函数本身并不会被执行,只有在调用时才会执行。