1、bash脚本编程:
选择执行:if单分支、if双分支、if多分支;case语句
2、case语句:
语法格式:
case $VARIABLE in //$VARIABLE是变量引用,in是关键字
PAT1)//模式1
分支1
;; //以双分号结束分支1语句
PAT2)
分支2
;;
...
*)//所有都不匹配,为*,类似else
分支n
;;
esca
注意:①、每个case中的模式语句必须以双分号结尾,这里的双分号可以单独成行,也可以放在每个分支的最后一条语句后面,PAT仅支持golb风格的通配符(*、?、[ ] 、[^ ])
②、case语句仅适用于一个变量与多个值分别做模式匹配时适用。
mem)display mem information
disk)display disk information
*) quit
正确的选择则给出相应的信息,否则,则提示重新选择正确的选项。
if语句实现: [root@localhost sh]# cat men.sh #!/bin/bash cat << EOF mem)display mem information disk)display disk information *) quit EOF read -p "enter your choice:" choice while [ "$choice" != "cpu" -a "$choice" != "mem" -a "$choice" != "disk" -a "$choice" != "*" ];do echo "please make sure your choice" read -p "enter your choice again:" choice done if [ "$choice" == "cpu" ];then lscpu elif [ "$choice" == "mem" ];then free elif [ "$choice" == "disk" ];then fdisk -l /dev/[hs]d[a-z] else echo "quit" exit 4 fi [root@localhost sh]# |
case语句实现: [root@localhost sh]# cat case.sh #!/bin/bash cat << EOF mem)display mem information disk)display disk information *) quit EOF read -p "enter your choice:" choice while [ "$choice" != "cpu" -a "$choice" != "mem" -a "$choice" != "disk" -a "$choice" != "*" ];do echo "please make sure your choice" read -p "enter your choice again:" choice done case $choice in cpu) lscpu;; mem) free ;; disk) fdisk -l /dev/[hs]d[a-z] ;; *) echo "quit" exit 4 esac [root@localhost sh]# |
4、示例:写一个服务脚本:$lockfile 值:/var/lock/subsys/SCRIPT_NAME
要求:此脚本可接受start、stop、restart、status四个参数之一
start,则创建lockfile,并显示启动
restart,则先删除此文件,再创建此文件,而后显示重启完成
status,如果lockfile存在,则显示running,否则,则显示为stopped
[root@localhost init.d]# cat testservice
#!/bin/bash
#chkconfig: - 50 50
#description: test service script
prog=$(basename $0)
lockfile=/var/lock/subsys/$prog
case $1 in
start)
if [ -f $lockfile ];then
echo "$prog is running yet"
else
touch $lcokfile
[ $? -eq 0 ] && echo "start $rpog finished"
fi
;;
stop)
if [ -f $lockfile ];then
rm -rf $lockfile
[ $? -eq 0 ] && echo "stop $prog finished"
else
echo "prog is not runing"
fi;;
restart)
if [ -f $lockfile ];then
rm -rf $lockfile
touch $lockfile
echo "restart $prog finished"
else
touch -f $lockfile
echo "start $prog finished"
fi;;
status)
if [ -f $lockfile ];then
echo "$prog is running"
else
echo "$prog is stopped"
fi;;
*)
echo "usage:$prog {start | stop | restart | status}"
exit 5;;
esac
[root@localhost init.d]#
测试:
[root@localhost init.d]# cp testservice.sh /etc/init.d/
[root@localhost init.d]# chkconfig --add testservice.sh
[root@localhost init.d]# chkconfig --list testservice.sh
[root@localhost init.d]# chmod +x /etc/init.d/testservice.sh
[root@localhost init.d]# service testservice.sh start
[root@localhost init.d]# ls /var/lock/subsys/ //每个启动的服务在此目录下都有一个锁文件。
5、函数:function;对于过程式编程来讲,函数是实现代码重用的主要组件之一。
5.1、函数的定义:把一段独立功能的代码当做一个整体,并为它命名一个名字,即命名的代码段。注意:函数的代码段不会自己执行,它只能在被调用时才执行。
5.2、函数的调用:在代码中给定函数名即可;函数名出现的问题,在代码执行时都会被自动的替换为函数代码。
①实现模块化编程
②实现结构化编程
5.4、函数的语法:
语法一: function f_name{ 函数体 } 注意:function是关键字,f_name是函数名,函数体在bash中编写的各类代码,无论是顺序的、选择的、循环的,都可以放在函数体中。 |
语法二: f_name( ) { 函数体 } |
注意:函数都有自己的生命周期:每次被调用时创建,返回时终止。
函数也有返回值:其状态返回结果为函数体中运行的最后一条命令的状态结果
5.5、自定义函数状态返回值:return
return用法:
return [0-255]
0:表示成功
1-255:表示失败
脚本的状态返回值:exit
exit用法:
exit [0-255]
0:表示成功
1-255:表示失败
5.6、函数示例:
未用函数实现: [root@localhost sh]# cat fun_user.sh #!/bin/bash if id "$1" &> /dev/null;then grep "^$1\>" /etc/passwd | cut -d: -f3,7 else echo "no such user" fi [root@localhost sh]# [root@localhost sh]# bash fun_user.sh root 0:/bin/bash [root@localhost sh]# |
用函数实现: [root@localhost sh]# cat fun_user2.sh #!/bin/bash username=$1 get-userinfo() { if id "${username}" &> /dev/null;then grep "^${username}\>" /etc/passwd | cut -d: -f3,7 else echo "no such user" fi } [root@localhost sh]# [root@localhost sh]# bash fun_user2.sh root 0:/bin/bash |
注意:$1在函数中有特殊的用法,因此,此处用其他定义的变量代替 | |
用函数实现,多次调用函数 [root@localhost sh]# cat fun_user3.sh #!/bin/bash get-userinfo() { if id "${username}" &> /dev/null;then grep "^${username}\>" /etc/passwd | cut -d: -f3,7 else echo "no such user" fi } username=$1 get-userinfo username=$2 get-userinfo [root@localhost sh]# |
注意:由于没有设置return状态返回值,因此函数的状态返回值是函数体执行的最后一条语句的状态返回值。
②、用函数实现服务脚本框架
[root@localhost sh]# cat fun_testservice.sh #!/bin/bash #chkconfig: - 50 50 #decription: function testservice prog=`basename $0` lockfile=/var/lock/subsys/$prog start() { if [ -f $lockfile ];then echo "$prog is running" else touch $lockfile && echo "start $prog finished" fi } stop() { if [ -f $lockfile ];then rm -f $lockfile [ $? -eq 0 ] && echo "stop $lockfile finished" else echo "$prog is not running" fi } status() { if [ -f $lockfile ];then echo "$prog is running" else echo "$prog is stopped" fi } usage() { echo "usage $prog {start | stop | status | restart}" } case $1 in start) start;; stop) stop;; restart) start stop ;; status) status;; *) usage exit 1 ;; esac [root@localhost sh]# 检查运行结果: [root@localhost sh]# bash fun_testservice.sh status [root@localhost sh]# bash fun_testservice.sh start [root@localhost sh]# bash fun_testservice.sh stop [root@localhost sh]# bash fun_testservice.sh restart [root@localhost sh]# bash fun_testservice.sh s |
5.7、函数返回值:(有两种)
函数的执行结果返回值:
①、使用echo或printf命令进行输出,需要注意的是,printf不会换行,但可以格式化
5.8、函数可以接受参数:
传递参数给函数:
在函数体当中,可以使用$1,$2,$3,.....$n引用传递给函数的参数,还可以使用$*,$@应用所有参数,$#引用传递给函数参数的个数
怎么传递参数给函数?
在调用函数时,在函数名后面以空白字符分割,给定参数列表即可,如:funcation arg1 arg2 ...
5.9、给函数传递参数示例:
添加10个用户,添加用户的功能使用函数实现,用户名作为参数传递给函数。
[root@localhost sh]# cat fun_add_user.sh
#!/bin/bash
#description: user function to add user,username is argument
#date: 20180106
toadduser() {
if id $1 &>/dev/null;then
return 5//判断如果用户存在,则返回函数退出状态码5
else
useradd $1
retval=$?//将useradd $1的执行结果状态码赋值给变量retval
return $retval
fi
}
for ((i=1;i<=10;i++));do
toadduser ${1}${i}
retval1=$?//此处将函数的执行状态结果传递给变量retval1,为了在elif判断中 不去引用if的执行状态结果,
if [ $retval1 -eq 5 ];then
echo "user ${1}${i} is exists"
elif [ $retval1 -eq 0 ];then
echo "user ${1}${i} add sucessfull"
else
echo "unkown error"
fi
done
[root@localhost sh]#
注意:如果在循环语句中要引用函数的执行状态结果,最好将函数的执行状态结果$?赋值给变量。
5.10、练习:
5.10.1、写一个脚本,实现如下功能:
①、使用函数实现ping一个主机来测试主机的在线状态,并统计在线和不在线主机数;主机地址通过参数传递给函数
②、主程序:测试172.16.1.1 - 172.16.67.1范围内各主机的在线状态。
[root@localhost sh]# cat fun_userping.sh
#!/bin/bash
declare -i m=0
declare -i n=0
userping(){
ping -W 1 -c 1 $1 &> /dev/null
retval=$?
if [ $retval -eq 0 ];then
echo "$1 is online"
let m++
else
echo "$1 is offline"
let n++
fi
}
for ((i=1;i<=67;i++));do
userping 172.16.${i}.1
done
echo "online $m,offline $n"
[root@localhost sh]#
5.10.2、写一个脚本,实现打印NN乘法表,打印乘法表用函数实现
[root@localhost sh]# cat fun_NN_chengfabiao.sh
#!/bin/bash
nn() {
for ((i=1;i<=$1;i++));do
for((j=1;j<=i;j++));do
echo -n -e "${i}*${j}=$[${i}*${j}]\t"
done
echo
done
}
nn $1
[root@localhost sh]#
5.11、变量作用域:
局部变量:作用域是函数的生命周期,在函数结束时,被自动销毁。
定义局部变量的方法:
在函数内部:local VARIABLE=VALUE //VARIABLE是变量名,value是变量值。
本地变量:作用域是运行脚本的shell的生命周期,因此,其作用范围为当前shell脚本程序文件。
示例说明:
[root@localhost sh]# cat var.sh #!/bin/bash name=tom setname() { name=jerry echo "function:$name" } setname echo "shell $name" [root@localhost sh]# [root@localhost sh]# bash var.sh function:jerry shell jerry [root@localhost sh]# |
[root@localhost sh]# cat var.sh #!/bin/bash name=tom setname() { local name=jerry echo "function:$name" } setname echo "shell $name" [root@localhost sh]# [root@localhost sh]# bash var.sh function:jerry shell tom [root@localhost sh]# |
输出结果都为jerry,原因是setname函数中定义的name可以调用脚本中定义的变量name |
|
注意:建议在写函数中的变量定义时,全部定义为局部变量,除非打算和主程序进行交互传递值。 |
5.12、函数递归:常用在阶乘、和数列中。
阶乘示例: [root@localhost sh]# cat fun_jc.sh #!/bin/bash fact() { if [ $1 -eq 0 -o $1 -eq 1 ];then echo 1 else echo $[$1*$(fact $[$1-1])] fi } fact $1 [root@localhost sh]# [root@localhost sh]# bash fun_jc.sh 4 24 [root@localhost sh]# |
数列示例: [root@localhost sh]# cat fun_sl.sh #!/bin/bash fab() { if [ $1 -eq 1 ];then echo -n "1 " elif [ $1 -eq 2 ];then echo -n "1 " else echo -n "$[$(fab $[$1-1])+$(fab $[$1-2])] " fi } for i in $(seq 1 $1);do fab $i done echo [root@localhost sh]# [root@localhost sh]# bash fun_sl.sh 10 1 1 2 3 5 8 13 21 34 55 |