shell脚本篇二---shell脚本写作

来源:互联网 发布:hecras软件中堰流系数 编辑:程序博客网 时间:2024/05/17 23:26

一、基本习惯的养成

1、脚本应该放在指定的位置

一般的,放在家目录的scripts内;执行脚本即需执行sh  sh01.sh即可,因为sh在bash中即位于/bin下;

使用-n  -x来校验脚本的语法是否正确;

2、脚本的书写规范 

一般的,需要在头部注明Program,Histoty,作者,时间,版本等信息

一般的,特殊的程序加上#进行注释会对以后查询很有帮助;

在内部程序,代码最好能以 [tab] 按键的空格向后推, 这样你的程序代码会显的非常的漂亮和有条理,在查阅和debug上也会很轻松

在主程序完成后,回传一个值给系统进行执行结果的告知,如exit 0,执行完后回传0给系统,此时去$?则显示为0,即执行成功;

二、简单的一些例子

1、让用户输入,和用户交互

read -p "please input your fist name:" firstname      #让用户输入它的第一个名字,并把该值赋予变量firstname

2、数值运算

+ - * / %(这里的%是取余数的意思)

var=$((数值运算式))或者可以delcare -i total=$firstnu*$secnu,建议使用前一种;

3、善于运用判断式

一般的,可以利用test命令进行测试

(1)关于文件的测试,如test  -e  filename

-e  该『档名』是否存在?(常用)
-f  该『档名』是否存在且为档案(file)?(常用)
-d  该『文件名』是否存在且为目录(directory)?(常用)

(2)关于某文件是否具有某些权限的测试,如test  -r  filename

-r  侦测该档名是否存在且具有『可读』的权限?
-w  侦测该档名是否存在且具有『可写』的权限?
-x  侦测该档名是否存在且具有『可执行』的权限?

(3)关于两个整数之间的判断

-eq  两数值相等 (equal)

-ne  两数值不等 (not equal)
-gt  n1 大亍 n2 (greater than)
-lt  n1 小亍 n2 (less than)
-ge  n1 大亍等亍 n2 (greater than or equal)
-le  n1 小亍等亍 n2 (less than or equal)

(4)关于字符串的判断

test -z string  刞定字符串是否为 0 ?若 string 为穸字符串,则为 true
test -n string  刞定字符串是否非为 0 ?若 string 为穸字符串,则为 false。注: -n 亦可省略
test str1 = str2 刞定 str1 是否等亍 str2 ,若相等,则回传 true
test str1 != str2 刞定 str1 是否丌等亍 str2 ,若相等,则回传 false

(5)多重条件判断,如test -r filename -a -x filename

-a  (and)两状况同时成立!例如 test -r file -a -x file,则 file 同时具有r 不 x 权限时,才回传 true。
-o  (or)两状况任何一个成立!例如 test -r file -o -x file,则 file 具有 r或者 x 权限时,就可回传 true。
!  反相状态,如 test ! -x file ,当 file 丌具有 x 时,回传 true

示例:让用户输入文件名称,并判断是否存在,若不存在则报告信息,若存在则判断其是否属于文件or目录,并判断其读写权限;

[root@www scripts]# vi sh05.sh
#!/bin/bash
# Program:
#  User input a filename, program will check the flowing:
#  1.) exist? 2.) file/directory? 3.) file permissions
# History:
# 2005/08/25  VBird  First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# 1. 讥使用者输入档名,幵且刞断使用者是否真的有输入字符串?
echo -e "Please input a filename, I will check the filename's type and \
permission. \n\n"
read -p "Input a filename : " filename
test -z $filename && echo "You MUST input a filename." && exit 0
# 2. 刞断档案是否存在?若不存在则显示讯息并结束脚本
test ! -e $filename && echo "The filename '$filename' DO NOT exist" &&
exit 0
# 3. 开始刞断文件类型不属性
test -f $filename && filetype="regulare file"
test -d $filename && filetype="directory"
test -r $filename && perm="readable"
test -w $filename && perm="$perm writable"
test -x $filename && perm="$perm executable"
# 4. 开始输出信息!
echo "The filename: $filename is a $filetype"
echo "And the permissions are : $perm"

4、利用[]做判断

[]做条件判断时一般用在if语句中。不过要注意,因为[]在bash的特殊字符和正则表达式中均有不同的含义,因此在shell脚本中,要注意,在[]中的每一个字符都要有空格隔开,例如          [□"$HOME"□==□"$MAIL"□]                            

                   ↑                ↑    ↑              ↑                                                              #这些都是空格的意思,否则将报错说参数(argument)过多;

5、shell脚本的默认参数$0,$1......

意思就是,对于shell脚本来说,在执行这个shell脚本(即在sh  scritname)的时候,可以带上参数$1,$2, $3...(即可以不用像read似得需要在执行的过程中输入参数), 这样的话就可以在shell脚本内直接使用$1,意思就是执行的时候输入的这个变量值;对于shell脚本来说,是支持这样做的,其默认的格式如下:

/path/to/scriptname   opt1   opt2   opt3   opt4

            $0                   $1      $2      $3      $4             #执行的脚本即为 $0 这个发量,第一个接的参数就是 $1 ,所以,只要我们在script 里面善用 $1 的话,就可以很简单的                                                                                                 立即下达某些命令功能

除了这些数字的发量之外, 我们还有一些较为特殊的变量可以在 script 内使用来呼出这些参数
$# :代表后面接的参数『个数』,以上表为例这里显示为『 4 』;
$@ :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
$* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字符,默认为空格键, 所以本例中代表『 "$1 $2 $3 $4" 』之意。

提示: $@ 和 $* 基本上还是有所不同,不过,一般使用情况下可以直接记忆 $@ 即可!

示例:[root@www scripts]# vi sh07.sh
#!/bin/bash
# Program:
#  Program shows the script name, parameters...
# History:
# 2009/02/17  VBird  First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
echo "The script name is ==> $0"
echo "Total parameter number is ==> $#"
[ "$#" -lt 2 ] && echo "The number of parameter is less than 2. Stop here." && exit 0
echo "Your whole parameter is ==> '$@'"
echo "The 1st parameter ==> $1"
echo "The 2nd parameter ==> $2"
执行结果如下:
[root@www scripts]# sh sh07.sh theone haha quot
The script name is ==> sh07.sh      <==脚本名称
Total parameter number is ==> 3     <==果然有三个参数
Your whole parameter is ==> 'theone haha quot'    <==参数的内容全部
The 1st parameter ==> theone    <==第一个参数
The 2nd parameter ==> haha      <==第二个参数

6、条件判断式

(1)利用if...then

a、单层,简单条件判断式,语法格式如下

if [ 条件刞断式 ]; then
当条件刞断式成立时,可以进行的指令工作内容;
fi                                                                                    #将 if 反过来写,就成为 fi 啦!结束 if 之意!

PS:除了可以将多个判断式写在一个[]之外,还可以写多个[],之间用&&(表示and)或者||(表示or)链接起来,比如[ "$yn" == "Y" -o "$yn" == "y" ]等同于[ "$yn" == "Y" ] || [ "$yn" == "y" ]

b、多重、复杂条件判断式,语法格式如下

if [ 条件刞断式一 ]; then
          当条件刞断式一成立时,可以进行的指令工作内容;
elif [ 条件刞断式二 ]; then                                                                              # elif 也是个刞断式,也有条件判断式,因此出现 elif 后面都要接 then 来处理;
          当条件刞断式二成立时,可以进行的指令工作内容;
else                                                                                                                # else是最后没有成立的结果了,所以后面没有 then 了;
          当条件刞断式一不二均不成立时,可以进行的指令工作内容;
fi      

(2)利用case...esac判断

 if是通过比对的方式进行判断的,而如果变量的数量有限,就可以通过case...esac来判断,语法如下

case $发量名称 in                               #关键词为 case ,还有变量前有钱字号
"第一个发量内容")                               #每个发量内容都建议用双引号括起来,关键词则为小括号 )
程序段
;;                                                           #每个类删结尾使用两个连续的分号来处理!
"第二个发量内容")
程序段
;;
*)                                                          #最后一个发量内容都会用 * 来代表所有其他值,不包含第一个发量内容与第二个发量内容的其他程序执行段
exit 1
;;
esac                                                      #最终的 case 结尾!『反过来写』思考一下!

示例:case $1 in 
"one")
echo "Your choice is ONE"
;;
"two")
echo "Your choice is TWO"
;;
"three")
echo "Your choice is THREE"
;;
*)
echo "Usage $0 {one|two|three}"       #若用户输入其他的变量,则提示只能使用这三个变量
;;
esac

(3)利用function功能

 即在脚本中自定义一个功能,后面可以进行调用,如上面的例子,因为都是同一个动作,则可以定义一个function,语法如下:

 function fname() {                                #这个 fname 就是要定义的function的名称 ,程序段就是要它执行的功能;注意,一般的要写在脚本的最前面;

        程序段
}
示例:function printit(){
echo -n "Your choice is "                                    # 加上 -n 可以丌断行继续在同一行显示
}
echo "This program will print your selection !"
case $1 in
"one")
printit; echo $1 | tr 'a-z' 'A-Z'                             # 将参数做大小写转换,并注意这里函数名称后面有一个;
;;
"two")
printit; echo $1 | tr 'a-z' 'A-Z'
;;
"three")
printit; echo $1 | tr 'a-z' 'A-Z'
;;
*)
echo "Usage $0 {one|two|three}"
;;
esac

说明:unction 也是拥有内建变量的,他的内建变量和 shell script 很类似, 函数名称代表示 $0 ,而后续接的变量也是以 $1, $2... 来定义的。 这里很容易搞错,因为『 function fname() { 程序段 } 』内的 $0, $1... 等等与 shell script 的 $0 是不同的。以上面 sh12-2.sh 来说,假如我下达:『 sh  sh12-2.sh one 』 这表示在 shell script 内的 $1 为 "one" 这个字符串。但是在 printit() 内的 $1 则与这个 one 无关

(4)循环语句

循环可以不断的执行某个程序段,直到用户定义的条件达成位为止,所以重点是哪个程序的达成条件是什么。除了这种依靠判断式是否达成的不定循环之外,还有一种已经固定要跑多少次的循环状态。
a、while do done语句,意思是当 condition 条件成立时,就进行循环,直到condition 的条件不成立才停止

while [ condition ]                      #中括号内的状态就是刞断式
do                                             #do 是循环的开始!
程序段落
done                                         #done 是循环的结束       

b、unitl do done语句,意思恰恰和while 相反,它说的是『当 condition 条件成立时,就终止循环, 否则就持续进行循环程序段(可知,until为真时,就直接跳过程序段)。

until [ condition ]
do
程序段落
done

c、for do done语句,for 这种语法,则是『 已经知道要进行几次循环』的状态!语法为

for var in con1 con2 con3 ...     

do      

程序段

done

说明:以上面的例子来说,这个 $var 的发量内容在循环工作时:1. 第一次循环时, $var 的内容为 con1 ; 2. 第二次循环时, $var 的内容为 con2 ;3. 第三次循环时, $var 的内容为 con3 ;  4. .... 

示例1:network="192.168.1"                                                            # 先定义一个网域的前面部分!
for sitenu in $(seq 1 100)                                                                # seq 为 sequence(连续) 的缩写之意
do
                                                                                                        # 底下的程序在叏得 ping 的回传值是正确的还是失败的!
ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 ||  result=1
                                                                                                        # 开始显示结果是正确的吪劢 (UP) 还是错误的没有连通 (DOWN)
if [ "$result" == 0 ]; then
echo "Server ${network}.${sitenu} is UP."
else
echo "Server ${network}.${sitenu} is DOWN."
fi
done

示例2:read -p "Please input a directory: " dir
if [ "$dir" == "" -o ! -d "$dir" ]; then
echo "The $dir is NOT exist in your system."
exit 1
fi
                                                                                 #  开始测试档案啰~
filelist=$(ls $dir)                                                       # 列出所有在该目录下的文件名
for filename in $filelist
do
perm=""
test -r "$dir/$filename" && perm="$perm readable"
test -w "$dir/$filename" && perm="$perm writable"
test -x "$dir/$filename" && perm="$perm executable"
echo "The file $dir/$filename's permission is $perm "
done
d、for do done的数值处理

除了上述之外,for done的另外一种写法为

for (( 初始值; 限制值; 执行步阶 ))
do
程序段
done
说明:这种语法适合于数值方式的运算当中,在 for 后面的括号内的三串内容意为:
  初始值:某个变量在循环当中的起始值,直接以类似 i=1 设定好;
  限制值:当变量的值在这个限制值的范围内,就继续进行循环。例如 i<=100;
  执行步阶:每作一次循环时,变量的发化量。例如 i=i+1(如果每次增加 1 ,则可以使用类似『i++』)

示例:read -p "Please input a number, I will count for 1+2+...+your_input: " nu
s=0
for (( i=1; i<=$nu; i=i+1 ))
do
s=$(($s+$i))
done
echo "The result of '1+2+3+...+$nu' is ==> $s"

三、脚本的测试及debug

 sh  [-nvx]  scripts.sh
参数说明:
-n :不要执行 script,仅查询语法的问题;
-v :再执行 sccript 前,先将 scripts 的内容输出到屏幕上;
-x :将使用到的 script 内容显示到屏幕上,这是很有用的参数,因为显示的都是指令,可以知道是哪个指令发生错误了。


脚本的学习,多看、多模仿、幵加以修改成自己的样式!』 是最块的学习手段了!网上有相当多的有用的 scripts ,可以将对方的 scripts 拿来,幵且改成适合自己主机的样子!另外,我们 Linux 系统本来就有很多的服务启动脚本, 可以直接以 vim 进入该 script 去查阅一下,通常立刻就知道该 script 的目的。