这周是最烧脑的一周,每天都沉迷在如何编写脚本中,我相信脚本这块让大家都很头疼,包括以后的工作肯定也离不开脚本。那么我们接下来针对脚本这块给大家做个详细的分析。
一、if语句
单分支:if判断条件;then
条件为真的分支代码
fi
双分支:if判断条件; then
条件为真的分支代码
else
条件为假的分支代码
fi
多分支:if判断条件1; then
条件为真的分支代码
elif判断条件2; then
条件为真的分支代码
elif判断条件3; then
条件为真的分支代码
else
以上条件都为假的分支代码
fi
if语句的基本格式就是以上的形式,那么下面的两个例子让你对if语句加深印象
1、编写脚本/root/bin/filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)
脚本思路(1)用read -p交互式让用户输入文件路径
(2)判断该文件是否存在,以防用户输入的文件是不存在的
(3)然后用-h,-d,-f分别判断文件是否为软连接,目录还是普通文件。
2、编写脚本/root/bin/checkint.sh,判断用户输入的参数是否为正整数
脚本思路(1)用read -p交互式提示用户输入数字
(2)判断用户是否输入的是正数
(3)判断用户输入的正数是否是小数,如何判断是否是小数,只用看是否带“.”就行
二、case语句
case变量引用in
pat1)
分支1
;;
pat2)
分支2
;;
*)
默认分支
;;
esac
case语句适用于判断输入的关键字,那么下来以例子的形式加深印象
1、判断用户输入的是yes或者是no。
脚本思路(1)read -p交互式提示用户输入字符串
(2)根据用户可能输入yes的各种形式去判断
(3)根据用户可能输入no的各种形式去判断
(4)除了yes或者no就给用户提示不知道输入的是什么意思
三、for语句
for变量名in列表;do
循环体
done
列表的生成方式:
(1)直接给出列表
(2)整数列表:(a) {start..end}
(b) $(seq [start [step]] end)
(3)返回列表的命令$(COMMAND)
(4)使用glob,如:*.sh
(5)变量引用;$@, $*
for循环只要针对数字,下面还用事例加深for印象
1、编写脚本,提示输入正整数n的值,计算1+2+…+n的总和
脚本思路(1)read -p交互式提示用户输入正整数n
(2)判断用户输入的是否是正整数,如果不是正整数提示用户后并退出
(3)如果输入的是正整数,用for循环,列表是从1到n,循环体就是let sum+=$i
(4)直到循环n次后结束,输出sum值就行
2、打印九九乘法表
次数用到for嵌套for
脚本思路(1)九九乘法表需要循环九次
(2)外面每循环一次,里面就需要从1×到$sum
(3)里面循环结束都需要换行,所以要在内部循环结束后加echo
执行结果如下:
for语句的第二种用法:
for ((exp1;exp2;exp3)) ;do
command ;
done
用流程图表示如下:
四、while语句和untile语句
while语句:
while CONDITION;do
循环体
done
untile语句:
until CONDIOION;do
循环体
done
为什么要把while和untile语句放一块呢,因为这两个的用法刚好相反,while中当CONDITION为真的时候会一直循环下去,直到CONDITION为假就退出脚本。而untile中当CONDITION为假的时候会一直循环下去,直到CONDITION为真就退出脚本。
while的特殊用法:
while read line ;do
循环体
done
依次读取文件里面的每一行,且将行赋值给变量line
例如:截取出来UID大于100且小于200的值
下面我们用例子给大家展示一下while的用法以及untile的用法
1、编写脚本,求100以内所有正奇数之和
脚本思路(1)先定义i和sum的基础值
(2)然后用while循环,条件就为i小于100就退出
(3)循环体为let sum+=$i和i每次加2
2、禁止某个用户登录
脚本思路(1)用who命令去查看,然后把该用户截取出来
(2)每0.5秒检查一次,看该用户是否登录
(3)如果条件为真,那么就推出循环,就把该用户kill掉
while还能创建无限循环
while true ;do
循环体
done
此处的CONDITION只要换成true或者:就行
五、continue用法
continue只是结束本次循环进入下次循环,所以continue的位置一定要考虑清楚
例如:计算前100正奇数数的和,但是51不相加。
脚本思路(1)先定义i,sum的基础值
(2)循环判断i是否小于等于100
(3)判断i是否等于51,如果等于51就不去执行后面的命令,跳过本次循环
(4)如果不是51,判断余数是否等于1,等于1就去执行let sum+=I
(5)循环结束后,输出sum的值就行
六、break的用法
脚本中遇到break就直接结束循环体,相对于continue是直接退出循环体,而不是退出本次循环
对于上面例子,如果把continue换成break就是相当与遇到51后就直接退出循环体。
七、shift用法
shift适用于不确定的位置参数
例子:输入参数a b c d,依次创建四个账户。
脚本思路(1)先判断该用户是否输入参数,如果没有输入参数就直接退出,并提醒用户输入参数
(2)判断第一个参数是否存在,如果存在就创建用户shift将第一个变量删除,第二个变量成为第一个变量
(3)直到最后一个参数变为第一个参数结束时,退出循环。
八、select语法
select非常适用于编辑菜单脚本
例子:编写一个菜单
脚本思路(1)用select生成菜单编号和菜单名称
(2)用case语法检测用户输入的关键字
(3)这里的PS3是更改多行提示符
九、trap的用法
trap适用于脚本中信号捕捉,可以屏蔽一些信号。
trap ‘‘信号忽略信号的操作
trap ‘-‘信号恢复原信号的操作
trap -p列出自定义信号操作
例子:
这个脚本只是针对trap的一些用法,大家可以去试试。
十、函数
函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分
函数和shell程序比较相似,区别在于:
Shell程序在子Shell中运行
而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改
定义一个函数:
function () {
...函数体...
}
删除一个函数:unset function
查看一个函数:declare -i function
脚本里面的返回值:return
return和exit的区别:return专应用于函数,相当于exit退出脚本,但是函数是当前Shell ,如果要用exit就直接退出了,所以需要用return。函数中尽量不写exit
生成环境函数:export -f function
我们的机器开机的时候在启动一些服务时候后面总是显示[ok]或者[FAILED]。这是通过调用/etc/init.d/functions/里面的函数实现的:
例子:
编写服务脚本/root/bin/testsrv.sh,完成如下要求
(1)脚本可接受参数:start, stop, restart, status
(2)如果参数非此四者之一,提示使用格式后报错退出
(3)如是start:则创建/var/lock/subsys/SCRIPT_NAME,并显示“启动成功”
考虑:如果事先已经启动过一次,该如何处理?
(4)如是stop:则删除/var/lock/subsys/SCRIPT_NAME,并显示“停止完成”
考虑:如果事先已然停止过了,该如何处理?
(5)如是restart,则先stop,再start
考虑:如果本来没有start,如何处理?
(6)如是status,则如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAMEis running...”
如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped...”
其中:SCRIPT_NAME为当前脚本名(testsrv.sh)-e文件路径判断该文件是否存在
执行结果如下:
有兴趣的可以看下是如何实现的
其中的代码如下:
f_start() {
ls /var/lock/subsys/testsrv.sh &> /dev/null
if [ $? -eq 0 ];then
action "该服务已经启动" true
else
touch /var/lock/subsys/testsrv.sh
action "启动成功" true
fi
}
f_stop() {
ls /var/lock/subsys/testsrv.sh &> /dev/null
if [ $? -eq 0 ];then
rm -f /var/lock/subsys/testsrv.sh
action "停止完成" false
else
action "该服务已经停止" false
fi
}
f_restart() {
f_stop &> /dev/null
f_start &> /dev/null
action "该服务已经重新启动" true
}
f_status() {
ls /var/lock/subsys/testsrv.sh &> /dev/null
if [ $? -eq 0 ] ;then
action "testsrv.sh is running..." true
else
action "testsrv.sh is stopped..." false
fi
}
echo $1 |egrep -o "\|\|\|\" &> /dev/null
[ $? -ne 0 ] && { echo "请准确输入!!"; exit 10; }
. /etc/init.d/functions
if [ "$1" == start ];then
f_start
elif [ "$1" == stop ];then
f_stop
elif [ "$1" == restart ];then
f_restart
else
f_status
fi
整体思路就是,定义四个函数f_start,f_stop,f_restart,f_status。然后在脚本里面掉调用这四个函数就行。
十一、数组
数组:(有稀疏格式,有连续格式)
创建数组时候先声明变量:(在脚本里面也是先声明数组)
declare -a数组名称声明普通数组
declare -A数组名称声明关联数组
关联数组与普通数组不能相互转换
创建数组:
一次只赋值一个的时候:数组名称[number]=名称weekdays[0]=Sunday
直接添加变量到数组中是最后一个:数组名称[${#数组名称(*)}]=val4
一次性赋值全部元素的时候,如果有特殊符号的时候需要加””:数组名称=(“val1”“val2”“val3”....)
例如:title=([0]=wang [1]=xiaoming [2]=”xiaohong”)
只赋值特定元素的时候:数组名称=([0]=“val1”[2]=“val2”....)
例如:title=([0]=wang [2]=xiaoming [4]=”xiaohong”)
交互式数组赋值:read -a数组名称
显示数组里面的变量:
显示单个数组里面的变量:echo ${数组名称[number]}
显示数组里面全部的变量:echo ${数组名称[*]}或者echo ${数组名称[@]}
显示数组里面全部变量的个数:echo ${#数组名称[*]}
删除数组里面的变量
删除数组中的单个变量:unset数组名称[number]
删除数组中的最后一个变量:unset数组名称[$[${#数组名称[*]}-1]]
删除整个数组:unset数组名称
declare -a查看数组
数组切片:
echo ${数组名称[*]:number1:number2}
number1:要跳过的元素个数
number2:要取出的元素个数
例子:编写脚本实现生成是个数字,比较出最大的和最小的数字
例子:编写一个脚本,把/var/log/*.log放入数组中,并计算出偶数下表的总行数
其实我们平时写脚本的时候,可以先在本上把思路写好,然后按照本上的思路先都敲出来,然后再慢慢排错,我感觉这样写脚本会比边想边敲代码效率会更高。大家可以去尝试一下!
但是每个人有每个人的学习方法,在此仅仅是建议。希望能够帮到大家!!
原文:http://13296637.blog.51cto.com/13286637/1965883