加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

循环语句和函数

发布时间: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脚本程序时,将一些需要重复使用的命令操作,定义为公共使用的语句块,即可称为函数
  • 合理使用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
    函数使用两种变量
    • 全局变量:在函数内部定义的变量,当前脚本主代码可以获取,脚本主代码定义变量,函数内部也可以获取
    • 局部变量:local 变量名,确保变量仅在函数内部使用 ,只能在函数内部使用
    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个脚本,导入公共函数,然后调用 函数,获取数据

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

      推荐文章
        热点阅读