循环语句和函数
发布时间:2020-12-15 23:01:32 所属栏目:安全 来源:网络整理
导读:第 4 章 循环语句和函数 编写一个好脚本的要素 逻辑结构定义清晰 脚本可以重用 多加入注释 学会调试脚本 echo配合exit命令或sleep命令 bash -x 脚本 知识要点 while语句、shift命令 case语句 shell函数应用 while 语句的结构 重复测试某个条件,只要条件成立
第
4
章 循环语句和函数
逻辑结构定义清晰
脚本可以重用
多加入注释
学会调试脚本
echo配合exit命令或sleep命令
bash -x 脚本
while语句、shift命令
case语句
shell函数应用
while
语句的结构
重复测试某个条件,只要条件成立则反复执行
while语句的各种用法
注意:while通过管道,会产生一个新的bash(shell)
While
语句应用示例
每5分钟输出一次时间到/tmp/time.txt
禁止使用计划任务
#!/bin/bash while true //死循环 do
date +%H%M >> /tmp/time.txt sleep 300 done
批量添加用户
用户名称以stu开头,按数字顺序进行编号
一共添加20个用户,即stu1、stu2、……、stu20
初始密码均设为123456
[[email?protected] ~]# cat uaddwhile.sh
#!/bin/bash PREFIX="stu" i=1 while (( $i <= 20 )) //循环条件:序号<=20 useradd ${PREFIX}$i echo "123456" | passwd --stdin ${PREFIX}$i &> /dev/null (( i++ )) [[email?protected] ~]# ./uaddwhile.sh
[[email?protected] ~]# grep "stu" /etc/passwd | tail -3 stu18:x:1028:1028::/home/stu18:/bin/bash stu19:x:1029:1029::/home/stu19:/bin/bash stu20:x:1030:1030::/home/stu20:/bin/bash
使用inotify-tools,实现自动同步备份
[[email?protected] ~]# cat /opt/rsync.sh
inotifywait -mrq -e modify,create,move,delete /bak/ | while read DIR EVENT FILE rsync -az --delete /bak/ rsync://10.10.10.1/share &>/dev/null done
[[email?protected] ~]# inotifywait -mrq -e modify,delete /bak/
/bak/ CREATE passwd /bak/ MODIFY passwd /bak/ DELETE passwd
分析当前主机中所有用户,哪些是普通用户,哪些是系统用户
cat /etc/passwd | cut -d: -f1,3 | tr : ‘ ‘ > file1
while read user uid if (( uid>=500 && uid<=600 )) then
echo "$user是普通用户" else
echo "$user是系统用户" fi
done < file1
猜商品价格游戏
通过变量RANDOM获得随机数
提示用户猜测并记录次数,猜中后退出循环
#!/bin/bash
PRICE=$(expr $RANDOM % 1000) TIMES=0 echo "商品实际价格为0-1000之间,猜猜看是多少?" while true #循环条件:ture read -p "请输入你猜测的价格数目:" INT let TIMES++ if [ $INT -eq $PRICE ] ; then #提示猜测并记录次数 echo "恭喜你答对了,实际价格是 $PRICE" echo "你总共猜测了 $TIMES 次" exit 0 #若猜中则退出脚本 elif [ $INT -gt $PRICE ] ; then #与实际价格比较,给出提示 echo "太高了!" echo "太低了!" fi
done
[[email?protected] ~]# ./pricegame.sh
商品实际价格为0-999之间,猜猜看是多少? 请输入你猜测的价格数目:500 太高了!
请输入你猜测的价格数目:250 太低了!
请输入你猜测的价格数目:375 请输入你猜测的价格数目:280 请输入你猜测的价格数目:265 请输入你猜测的价格数目:253 恭喜你答对了,实际价格是 253 你总共猜测了 6 次
shift
迁移语句
用于迁移位置变量,将 $1~$9 依次向左传递
例如,若当前脚本程序获得的位置变量如下:
$1=file1、$2=file2、$3=file3、$4=file4
则执行一次shift命令后,各位置变量为:
$1=file2、$2=file3、$3=file4
再次执行shift命令后,各位置变量为:
$1=file3、$2=file4
应用示例:
通过命令行参数传递多个整数值,并计算总和
[[email?protected] ~]# vi test.sh
#!/bin/bash
n=1 while (($# > 0)) echo $$n is $1 && ((n++)) shift
done
应用示例:
通过命令行参数传递多个整数值,并计算总和
[[email?protected] ~]# vi showday.sh
Result=0 Result=$((Result+$1)) shift
done
echo "The sum is : $Result“ [[email?protected] ~]# ./sumer.sh 12 34 56
The sum is : 102
case
语句的结构
针对变量的不同取值,分别执行不同的命令序列
击键类型识别
提示用户输入一个字符
判断出该字符是字母、数字或者其他字符
read -p "请输入一个字符,并按Enter键确认:" KEY
case "$KEY" in [a-z]|[A-Z]) echo "您输入的是 字母。" ;; [0-9]) echo "您输入的是 数字。" *) echo "您输入的是 空格、功能键或其他控制字符。" esac
[[email?protected] ~]# ./hitkey.sh
请输入一个字符,并按Enter键确认:k
您输入的是 字母 k 。
[[email?protected] ~]# ./hitkey.sh 请输入一个字符,并按Enter键确认:8
您输入的是 数字 8 。
[[email?protected] ~]# ./hitkey.sh 请输入一个字符,并按Enter键确认:^[[19~ 您输入的是 空格、功能键或其他控制字符。
数字范围识别
判断分数范围,分出优秀、合格、不合格三档
[[email?protected] ~]# cat test.sh
read -p "请输入您的分数(0-100):" GRADE case "$GRADE" in 100|9[0-9]|8[5-9]) echo "$GRADE 分!优秀" 8[0-4]|[67][0-9]) echo "$GRADE 分,合格" #大于等于85小于等于100 echo "$GRADE 分?不合格" #大于等于60小于等于84 esac
编写系统服务脚本
使用start、stop、restart等参数来控制服务
服务控制指令通过位置变量$1传入
能够通过chkconfig命令来管理此服务
[[email?protected] ~]# cat /etc/init.d/myprog
#!/bin/bash
# chkconfig: - 90 10 #用于chkconfig识别的配置
# description: Startup script for sleep Server
case "$1" in #根据$1传入的控制指令分别执行不同操作 start) echo 正在启动$0服务 stop) echo 正在停止$0服务 restart|reload) $0 stop $0 start *) echo "用法: $0 {start|stop|restart}" esac
Shell
函数应用
Shell函数概述
Shell函数由两部分组成:
函数名(在一个脚本中必须唯一)
函数体(命令或语句集合)
定义新的函数(必须先定义后使用)
调用已定义的函数
向函数内传递参数(可以使用位置参数)
在脚本中定义一个加法函数,用于计算2个整数的和
调用该函数计算(12+34)、(56+789)的和
adder() {
echo $(($1 + $2)) }
adder 12 34
adder 56 789
[[email?protected] ~]# ./adderfun.sh
46
845
新安装的mysql配置管理员密码的函数
默认新安装的mysql管理员密码为空
mysqlpass()
{
mysql -u root -e "use test;" if (($?==0)) then
mysqladmin -uroot password ‘123‘ && echo "mysql密码修改成功" else
echo "mysql无法修改密码" exit 1 fi
}
检查rpm包的函数
如果rpm已经安装,则显示“包 is installed”
如果rpm包未安装,则用yum安装,安装好显示“包 install ok
checkRPM() {
for i #就是for i in [email?protected]获取所有位置参数 do
if ! rpm -q "$i" &> /dev/null echo "please wait a moment" yum install "$i" -y &> /dev/null echo "$i install ok" echo "$i is installed" done
checkRPM httpd mysql mysql-server php php-mysql
[[email?protected] ~]# ./test.sh
httpd is installed
please wait a moment mysql install ok mysql-server install ok php install ok php-mysql install ok
如果rpm包未安装,则用yum安装,安装好显示“包 install ok”
如果希望是在运行脚本的时候输入位置参数
若要./test1.sh httpd mysql-server php php-mysql
for i #就是for i in [email?protected]获取所有位置参数
checkRPM [email?protected] [[email?protected] ~]# ./22.sh httpd mysql mysql-server php php-mysql
函数的退出状态有两种方式
默认退出状态:函数的最后一条命令返回的退出状态
使用return命令:以特定的退出状态退出函数
return只能在函数内部使用,默认是0
函数内部return之后的代码不会内执行
使用函数输出:直接将函数的结果赋值给变量
函数默认退出状态:函数的最后一条命令返回的退出状态
[[email?protected] ~]# cat test1.sh
func() { rpm -q sadfsdf &> /dev/null echo ‘$?‘ is $? ls /etc/passwd func
echo func exit status is $? [[email?protected] ~]# bash test2.sh $? is 1 /etc/passwd
func exit status is 0 [[email?protected] ~]# cat test2.sh
[[email?protected] ~]# bash test2.sh $? is 0 func exit status is 1
函数使用retun命令指定退出状态,只能用于函数返回值。
addUser()
for i in [email?protected] if [[ $i == haha ]]; then return 14 #return指定退出状态,后面的语句不会执行 useradd $i addUser [email?protected] echo $? [[email?protected] ~]# ./test.sh xixi haha hehe
14
[[email?protected] ~]# grep hehe /etc/passwd [[email?protected] ~]# #hehe没有创建
直接将函数的结果赋值给变量
[[email?protected] ~]# cat test.sh
func () du -sh $1 | tr -d ‘t‘| cut -d‘/‘ -f1 size=$(func $1) #直接将函数的输出赋值给变量 echo $1目录占用空间是:$size [[email?protected] ~]# ./test.sh /etc
/etc目录占用空间是:33M
[[email?protected] ~]# ./test.sh /usr/local /usr/local目录占用空间是:140K
函数比内部命令优先
num1(){
for i in $(seq $1) ; do echo -n 1 done
num2(){ ((j=32-$1)) for i in $(seq $j) ; do echo -n 0 a=$(num1 $1) b=$(num2 $1) echo $a$b
函数使用两种变量
func ()
echo a is $a b=100 a=200 echo b is $b local b=100
函数库文件
如果多个脚本需要调用重复的函数,没必要在每个脚本中定义,只需要创建函数库文件,将需要的函数都放到这个库文件
每个脚本只需要一条语句调用库文件即可
注意不能把库文件当做普通脚本一样在脚本中运行,那样那些函数将不会出现在脚本中
可以存放公共
创建库文件
在脚本中调用库文件(注意库文件的路径)
还可以将库文件在.bashrc中定义
source /opt/lib.sh
全局函数可以在当前shell的所有子shell中随意运行
exprot -f port #将函数输出为全局函数
实验案例
1
编写脚本生成2位的随机数,要求个位和十位数不能相同,如果遇到个位和十位相同的就退出脚本(注意十位数不能为0)
[[email?protected] ~]# exp1
61
57
81
51
65
31
连续成功7次
[[email?protected] ~]# exp1 连续成功0次
[[email?protected] test4]# exp1 23
连续成功1次
[[email?protected] test4]# exp1 85
74
97
连续成功4次
给登录到当前主机的所有非root用户终端发送一句话“用户名: Hi,I’m Root!”
[[email?protected] ~]# vi hello.sh
who | grep -v ^root | tr -s ‘ ‘ | cut -d ‘ ‘ -f1,2 > file1 while read user tty echo "$user : Hi,I‘m Root!" > /dev/$tty done < file1
根据前面猜价格的脚本,编写猜10以内的随机数的脚本,显示效果如下
每个人只有3次机会,超过3次没有猜中自动退出
编写del.sh脚本实现批量删除用户,脚本要求如下(使用while循环读取来改写上次的for脚本)
提示输入需要删除的用户名前缀,如果用户名前缀为空或者空格,就显示“请输入合法用户名前缀”,然后退出脚本,每删除一个用户,要显示“用户用户名 已经成功被删除”。如果没有可以删除的用户,就显示“以用户前缀开头的用户不存在”。最后要显示删除的用户总数是“一共新建的用户数:数目”
注意不能删除管理员或者系统用户(UID小500或者大于60000)
编写脚本显示如下图所示效果,要求选择一个菜单后,不用按回车,马上实现菜单相应的功能,显示完毕按任意键回到菜单,输入0退出菜单
、
***Menu***
1. Display disk space
2. Display interface information
3. Display memory usage
0. Exit menu
Enter option: 4
Sorry,wrong selection
Press any key to continue Enter option:
文件系统 容量 已用 可用 已用%% 挂载点
/dev/sda2 367G 9.6G 339G 3% /
tmpfs 1.9G 124K 1.9G 1% /dev/shm
/dev/sda1 97M 30M 63M 33% /boot
检查服务的函数,显示效果如图所示
检查服务状态,启动的要显示正常,未启动的要重启
重启后再次检查,还未启动的,要显示服务有问题
要检查服务名称是否错误
先停止FTP服务,然后故意改错FTP的配置文件
[[email?protected] ~]# service vsftpd stop 关闭 vsftpd: [确定] [[email?protected] ~]# echo dsalkjf >> /etc/vsftpd/vsftpd.conf [[email?protected] ~]# ./test.sh smb vsftpd httpd smb 状态正常
500 OOPS: missing value in config file for: dsalkjf vsftpd服务有问题
httpd 状态正常
[[email?protected] test5]# ./test.sh httpd samba 服务名称错误 httpd重启后已经ok
samba服务不存在,请检查问题
检查侦听端口的函数,显示效果如图所示
输入一个参数检查侦听的端口,如果有侦听,显示端口和侦听的进程名称(要区分是udp还是tcp),如果端口没有侦听,则显示“端口未侦听”
[[email?protected] ~]# ./test.sh 21
vsftpd正在侦听:tcp21端口
[[email?protected] ~]# ./test.sh 980 rpcbind正在侦听:udp980端口
[[email?protected] ~]# ./test.sh 53 53端口没有侦听
编写时间检查脚本
编写时间检查函数,算出当前时间离各个时间参照点的小时分钟差值,显示效果如下
2013年 07月 18日 星期四 08:40:00 CST
[[email?protected] opt]# ./time.sh 离上午上课还差0小时5分钟
[[email?protected] opt]# date -s 845 2013年 07月 18日 星期四 08:45:00 CST
[[email?protected] opt]# ./time.sh 上午上课时间到,躁起来,娭毑们
[[email?protected] opt]# date -s 1121 2013年 07月 18日 星期四 11:21:00 CST
[[email?protected] opt]# ./time.sh 离中午吃饭时间还有0小时24分钟
[[email?protected] opt]# date -s 1145
2013年 07月 18日 星期四 11:45:00 CST
[[email?protected] opt]# ./time.sh 开饭喽,同志们冲啊
[[email?protected] opt]# date -s 13:01 2013年 07月 18日 星期四 13:01:00 CST
[[email?protected] opt]# ./time.sh 午休,离下午上课时间还有0小时59分钟
[[email?protected] opt]# date -s 1539 2013年 07月 18日 星期四 15:39:00 CST
[[email?protected] opt]# ./time.sh 离放学时间还有1小时51分钟
编写获取配置文件中的数据的脚本
有多个脚本需要从配置文件中获取数据:
IP、端口、服务名、用户名、密码
写公共函数,通过参数来实现获取上面需要的dsN的数据
编写2个脚本,导入公共函数,然后调用 函数,获取数据
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |