循环语句和函数

第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
do
    useradd ${PREFIX}$i
    echo "123456" | passwd --stdin ${PREFIX}$i &> /dev/null
 (( i++ ))
done
[[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
do
        rsync -az --delete /bak/ rsync://10.10.10.1/share &>/dev/null
done
[[email protected] ~]# inotifywait -mrq -e modify,create,move,delete /bak/
/bak/ CREATE passwd
/bak/ MODIFY passwd
/bak/ DELETE passwd

分析当前主机中所有用户,哪些是普通用户,哪些是系统用户

#!/bin/bash
cat /etc/passwd | cut -d: -f1,3 | tr : ‘ ‘ > file1
while read user uid
do
 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
do
 read -p "请输入你猜测的价格数目:" INT
 let TIMES++
 if [ $INT -eq $PRICE ] ; then #提示猜测并记录次数
 echo "恭喜你答对了,实际价格是 $PRICE"
 echo "你总共猜测了 $TIMES 次"
 exit 0                 #若猜中则退出脚本
 elif [ $INT -gt $PRICE ] ; then #与实际价格比较,给出提示
 echo "太高了!"
 else
 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))
do
  echo \$$n is $1 && ((n++))
  shift
done

应用示例:

通过命令行参数传递多个整数值,并计算总和

[[email protected] ~]# vi showday.sh
#!/bin/bash
Result=0
while (($#  > 0))
do
 Result=$((Result+$1))
    shift
done
echo "The sum is : $Result“
[[email protected] ~]# ./sumer.sh  12 34 56
The sum is : 102 

case语句的结构

针对变量的不同取值,分别执行不同的命令序列

case语句应用示例

击键类型识别

提示用户输入一个字符

判断出该字符是字母、数字或者其他字符

#!/bin/bash
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函数由两部分组成:

函数名(在一个脚本中必须唯一)

函数体(命令或语句集合)

定义新的函数(必须先定义后使用)

调用已定义的函数

向函数内传递参数(可以使用位置参数)

Shell函数应用示例

应用示例:

在脚本中定义一个加法函数,用于计算2个整数的和

调用该函数计算(12+34)、(56+789)的和

#!/bin/bash
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
 then
 echo "please wait a moment"
                        yum install "$i" -y &> /dev/null
 echo "$i install ok"
 else
 echo "$i is installed"
 fi
 done
}
checkRPM httpd mysql mysql-server php php-mysql
[[email protected] ~]# ./test.sh
httpd is installed
please wait a moment
mysql install ok
please wait a moment
mysql-server install ok
please wait a moment
php install ok
please wait a moment
php-mysql install ok

检查rpm包的函数

如果rpm已经安装,则显示“包 is installed”

如果rpm包未安装,则用yum安装,安装好显示“包 install ok”

如果希望是在运行脚本的时候输入位置参数

若要./test1.sh httpd mysql-server php php-mysql

checkRPM() {
 for i   #就是for i in [email protected]获取所有位置参数
 do
 if ! rpm -q "$i" &> /dev/null
 then
 echo "please wait a moment"
                        yum install "$i" -y &> /dev/null
 echo "$i install ok"
 else
 echo "$i is installed"
 fi
 done
}
checkRPM [email protected]

[[email protected] ~]# ./22.sh httpd mysql mysql-server php php-mysql
httpd is installed
please wait a moment
mysql install ok
please wait a moment
mysql-server install ok
please wait a moment
php install ok
please wait a moment
php-mysql install ok

函数返回值

函数的退出状态有两种方式

默认退出状态:函数的最后一条命令返回的退出状态

使用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
func() {
 ls /etc/passwd
 echo ‘$?‘ is $? 
   rpm -q sadfsdf &> /dev/null 
}
func
echo func exit status is $?
[[email protected] ~]# bash test2.sh
/etc/passwd
$? is 0
func exit status is 1

函数使用retun命令指定退出状态,只能用于函数返回值。

addUser()
{
 for i in [email protected]
 do
 if [[ $i == haha ]]; then
 return 14     #return指定退出状态,后面的语句不会执行
 else
 useradd $i
 fi
 done
}
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
done
}
a=$(num1 $1)
b=$(num2 $1)
echo $a$b

函数中的变量

函数使用两种变量

  • 全局变量:在函数内部定义的变量,当前脚本主代码可以获取,脚本主代码定义变量,函数内部也可以获取
  • 局部变量:local 变量名,确保变量仅在函数内部使用 ,只能在函数内部使用
func ()
{
 echo a is $a
  b=100
}
a=200
func
echo b is $b
func ()
{
 echo a is $a
  local b=100
}
a=200
func
echo b is $b

函数库文件应用

函数库文件

如果多个脚本需要调用重复的函数,没必要在每个脚本中定义,只需要创建函数库文件,将需要的函数都放到这个库文件

每个脚本只需要一条语句调用库文件即可

注意不能把库文件当做普通脚本一样在脚本中运行,那样那些函数将不会出现在脚本中

可以存放公共

创建库文件

在脚本中调用库文件(注意库文件的路径)

还可以将库文件在.bashrc中定义

source /opt/lib.sh

全局函数可以在当前shell的所有子shell中随意运行

exprot -f port     #将函数输出为全局函数

案例

实验案例1

编写脚本生成2位的随机数,要求个位和十位数不能相同,如果遇到个位和十位相同的就退出脚本(注意十位数不能为0)

[[email protected] ~]# exp1
61
57
81
51
51
65
31
连续成功7次
[[email protected] ~]# exp1
连续成功0次
[[email protected] test4]# exp1
23
连续成功1次
[[email protected] test4]# exp1
85
46
74
97
连续成功4次

实验案例2

给登录到当前主机的所有非root用户终端发送一句话“用户名: Hi,I’m Root!”

[[email protected] ~]# vi hello.sh
#!/bin/bash
who | grep -v ^root | tr -s ‘ ‘ | cut -d ‘ ‘ -f1,2 > file1
while read user tty
do
 echo "$user : Hi , I‘m Root!" > /dev/$tty
done < file1

实验案例3

根据前面猜价格的脚本,编写猜10以内的随机数的脚本,显示效果如下

每个人只有3次机会,超过3次没有猜中自动退出

实验案例4

编写del.sh脚本实现批量删除用户,脚本要求如下(使用while循环读取来改写上次的for脚本)

提示输入需要删除的用户名前缀,如果用户名前缀为空或者空格,就显示“请输入合法用户名前缀”,然后退出脚本,每删除一个用户,要显示“用户用户名 已经成功被删除”。如果没有可以删除的用户,就显示“以用户前缀开头的用户不存在”。最后要显示删除的用户总数是“一共新建的用户数:数目”

注意不能删除管理员或者系统用户(UID小500或者大于60000)

实验案例6

编写脚本显示如下图所示效果,要求选择一个菜单后,不用按回车,马上实现菜单相应的功能,显示完毕按任意键回到菜单,输入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
                        ***Menu***
        1.      Display disk space
        2.      Display interface information
        3.      Display memory usage
        0.      Exit menu
                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
                        Press any key to continue

实验案例7

检查服务的函数,显示效果如图所示

检查服务状态,启动的要显示正常,未启动的要重启

重启后再次检查,还未启动的,要显示服务有问题

要检查服务名称是否错误

先停止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服务不存在,请检查问题

实验案例8

检查侦听端口的函数,显示效果如图所示

输入一个参数检查侦听的端口,如果有侦听,显示端口和侦听的进程名称(要区分是udp还是tcp),如果端口没有侦听,则显示“端口未侦听”

[[email protected] ~]# ./test.sh 21
vsftpd正在侦听:tcp21端口
[[email protected] ~]# ./test.sh 980
rpcbind正在侦听:udp980端口
[[email protected] ~]# ./test.sh 53
53端口没有侦听

实验案例9

编写时间检查脚本

编写时间检查函数,算出当前时间离各个时间参照点的小时分钟差值,显示效果如下

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分钟

实验案例10

编写获取配置文件中的数据的脚本

有多个脚本需要从配置文件中获取数据:

IP、端口、服务名、用户名、密码

写公共函数,通过参数来实现获取上面需要的dsN的数据

编写2个脚本,导入公共函数,然后调用 函数,获取数据

原文地址:https://www.cnblogs.com/qluzzh/p/10322536.html

时间: 2024-10-13 20:54:29

循环语句和函数的相关文章

理论+实操:shell之case语句for/while/until循环语句、函数、数组-满满的干货

前言: 单引号表示纯符号 用双引号表字符串 case多分支语句 循环语句 for循环语句 while循环语句 until循环语句 shell函数 shell数组 一 : case语句的结构 1.1 case结构 多分支表现形式:if语句,case语句 case 语句可以使用正则表达式,正则表达式后面会去阐述 针对变量的不同取值,分别执行不同的命令程序 case 中::表示一句话的结束 如果匹配某一个固定值,大多数用caes,其适用于某一个固定值 如果匹配某一个区间范围,大多数用if else 语

#9.5课堂JS总结#循环语句、函数

一.循环语句 1.for循环 下面是 for 循环的语法: for (语句 1; 语句 2; 语句 3) { 被执行的代码块 } 语句 1 在循环(代码块)开始前执行 语句 2 定义运行循环(代码块)的条件 语句 3 在循环(代码块)已被执行之后执行 2.for-in语句 for-in语句是一种精准的迭代语句,可以用来枚举对象的属性. 下面是for-in语句的语法: for(property in expression) statement demo: for(var propName in w

javascript循环语句及函数

循环语句 1.While 语法: while (exp) { //statements; } 说明: while (变量<=结束值) { 需执行的代码 } 例1: var i = 1; while(i < 3){ alert(i); i++; } 注意:如果忘记增加条件中所用变量的值,该循环永远不会结束.这可能导致浏览器崩溃. ( 用while输出1-1000的数值 var i=1; while(i<=1000){ if(i%2){ document.write(i); } //输出1-

Javascript语法,变量类型,条件,循环语句,函数,面向对象

1.JavaScript代码革两种存在形式: <!-- 方式一 --> <script type='txt/javascript' src='/js/comment.js'></script> <!-- 方式二 --> <script type='txt/javascript'> js代码内容 </script> 方式一可以有效提高代码的重用性 2.JavaScript代码存放位置 HTML的head中 HTML的body代码块底部(

for循环语句/命名函数

for(1.表达式1;2.表达式2;3.表达式3){ 4.循环体语句; } 先执行1,在执行2表达式,如果2的表达式为false的话直接退出循环, 如果2的表达式结果为true,执行4,执行3,执行2. break与continue区别: // break直接结束本循环 //continue:结束本次循环,进入下一个循环 <!doctype html> <html> <head> <meta charset="utf-8"> <ti

条件判断式if和循环语句while及其函数的应用

条件判断式 if..then.case..esac if..then 是最常见的条件判断式,就是当负某个条件判断的时候,就进行某项工作 ,其中"&&"代表AND,"||"代表or if....then..else...fi 格式: if [条件判断语句]: then 当条件判断成立时,可以进行的命令工作内容: fi       // 结束if条件判断 例子:设定  A=3,判断,如果A要是等于3,就会显示3 if [ $A = 3 ]; then  

input()函数和while循环语句

1.函数input()的工作原理 函数input()让程序暂停运行,等待用户输入一些文本.获取用户的输入后,python将其存储在一个变量里,方便稍后使用. 使用函数int()来获取数值的输入: 当用户使用input()函数时,python将用户的输入解读成字符串,但是如果用户想要进行数值计算的时候,则需要将字符串转换为数字 age = inpt() int(age) 求模运算符:% 该运算符是将两个数字相除,并返回其余数.例如可以用%来判读一个数是否能被另外一个数字整除.假如取模的结果为0,则

Shell编程之case多分支语句、循环语句(for、while等)、Shell函数、Shell数组

case多分支语句 case语句的结构: 针对变量的不同取值,分别执行不同的命令列 case 变量值 in 模式1) 命令序列1 ;; 模式2) 命令序列2 ;; ..... *) 默认命令序列 esac 示例: 字符类型识别: 提示用户输入一个字符: 判断出该字符是字母.数字或者其他字符. 脚本如下: [[email protected] opt]# vim test01.sh #!/bin/bash read -p "请输入一个字符:" key case $key in [a-z]

Python循环语句

Python语言中的循环结构包含两种语句,分别是while语句和for语句. 1. while语句 while(表达式): -- else: -- 执行过程:当循环表达式为True时,依次执行while中的语句.直到循环表达式的值为False时,才执行else语句或退出循环.其中else子句可以省略,表达式两端的等号也可以省略. 2. for语句 for循环用于遍历一个集合,依次访问集合中的每个项目.格式如下: for 变量 in 集合: -- else: -- 执行过程:每次循环从集合中取出一