当前位置:首页 > Liunx > 正文内容

shell函数与case语句-04

邓鹏10个月前 (01-13)Liunx170

#课程目标

  • 能使用RANDOM变量产生随机数

  • 理解嵌套循环

  • 掌握case语句的基本语法结构

  • 掌握函数的定义及调用

  • 掌握常用的正则表达式元字符含义

随机数

bash默认有一个$RANDOM的变量, 默认范围是0~32767.

使用set |grep RANDOM查看上一次产生的随机数

# echo $RANDOM19862# set |grep RANDOMRANDOM=19862

除法与余数

7除以3,商为2,余数为16除以2,商为3,余数为0可通过除以2,判断余数是否为1来判断是否为奇数(单数),如1,3,5,7,9可通过除以2,判断余数是否为0来判断是否为偶数(双数),如2,4,6,8,10

示例:

#!/bin/bashread -p "输入一个数字:" numif [ $[$num%2] -eq 1 ];then   # if双分支判断$num除以2的余数是否为1来确认是奇数还是偶数 echo "$num是奇数"else echo "$num是偶数"fi

产生自定义范围的随机数

产生0~1之间的随机数

# echo $[$RANDOM%2]      # 除以2,余数只可能是0或1

产生0~2之间的随机数

# echo $[$RANDOM%3]      # 除以3,余数只可能是0或1或2

产生1-2之内的随机数

# echo $[$RANDOM%2+1]     # 除以2,余数只可能是0或1,但都加1后,就只可能是1或2

产生50-100之内的随机数

# echo $[$RANDOM%51+50]     # 除以51,余数只可能是0到50,但都加50后,就只可能是50到100

产生三位数的随机数(100-999)

# echo $[$RANDOM%900+100]    # 除以900,余数只可能是0到899,但都加100后,就只可能是100到999# echo $[$RANDOM%9+1]$[$RANDOM%10]$[$RANDOM%10]


示例: 写一个猜数字的小游戏

#!/bin/bashecho "猜一个1-100的整数,猜对砸蛋:"   # 通过echo输出游戏规则num=$[$RANDOM%100+1]  # 产生1-100的随机数,赋值给num变量(余数为0-99,加1后余数为1-100)while true        # 死循环,条件true表示永远为真do          # 循环体开始 read -p "请猜:" gnum       # 交互模式让用户猜一个数字,将此数字赋值给gnum变量    if [ $gnum -gt $num ];then   # 多分支判断开始  echo "大了"        # 如果猜的数字大于随机数则报大了 elif [ $gnum -lt $num ];then   echo "小了"        # 如果猜的数字小于随机数则报小了 else   echo "对了"        # 如果猜的数字不大也不小,那么肯定就对了  break       # 猜对了就不要继续猜了,跳出循环 fi         # 多分支判断结束done         # 循环体结束(do与done之间的代码会循环)echo "砸蛋"         # 猜对了,跳出循环后则执行循环体外的代码

示例: 在上面的基础上加上一个条件,如果5次没猜对就退出游戏

#!/bin/bashecho "猜1-100内的一个整数,猜对有奖"num=$[$RANDOM%100+1]for i in {1..5}do        read -p "你猜:" gnum        if [ $gnum -gt $num ];then                echo "大了"        elif [ $gnum -lt $num ];then                echo "小了"        else                echo "对了"                break        fi        if [ $i -eq 5 ];then                echo "5次机会用完了,退出"                exit        fidoneecho "发奖"



嵌套循环

一个==循环体==内又包含另一个完整的循环结构,称为循环的嵌套。

在外部循环的每次执行过程中都会触发内部循环,直至内部完成一次循环,才接着执行下一次的外部循环。

for循环、while循环和until循环可以相互嵌套。

如: 我们一天中上午,下午,晚上都在学习,然后连续学习三天


上午下午晚上
第1天学习学习学习
第2天学习学习学习
第3天学习学习学习

1天上午

1天下午

1天晚上


2天上午

2天下午

2天晚上


3天上午

3天下午

3天晚上


示例:

for i in {a..c}      # 外层循环a,b,c三个字母do         # 外循环体开始        for j in {1..3}    # 内存循环1,2,3三个字母        do       # 内循环体开始                echo $i$j   # 一共循环3*3=9次,分别打印a1,a2,a3,b1,b2,b3,c1,c2,c3        done      # 内循环体结束done        # 外循环体结束

1555471413323



示例

先回顾echo命令:echo默认打印会换行echo -n打印不换行echo -e会让/n为换行号,\t为制表符(tab键)# echo -e "你\n好\t吗"你好      吗

示例: 打印出如下结果

***************分析: 1,一共5行,所以可以外部循环5次2,每行不换行打印与行数相等次数的*号(第1行循环1次,第2行循环2次......第5行循环5次)  内部循环次数与行数一致3,每行打印完*号会换行
#!/bin/bashfor i in $(seq 5)     # 外循环1-5,代表5行do        for j in $(seq $i) # 内循环,每行循环次数和行数保持一致(第1行循环1次,第2行循环2次...)        do                echo -n "*"  # 内循环每次不换行打印*        done             echo  # 每次打完一行的*号后使用echo换行(比如第3行,循环打完3个*号后换行)done

示例:打印出如下结果

112123123412345
#!/bin/bashfor i in $(seq 5)     # 执行seq 5这个命令产生1-5的序列,也一样实现1-5的循环do        for j in $(seq $i)   # seq命令后可接变量,{1..$i}这种就不行        do                echo -n $j        done        echodone


练习

1, 建立a1, a2, a3, a4, a5, b1, b2, b3, b4, b5。。。。。。。以此类推,一直到e1,e2, e3, e4, e5一共25个用户, 每个用户密码为随机三位数字(100-999), 并将用户名与密码保存到/root/.passwd文件中

#!/bin/bashrm -rf /root/.passwdfor i in {a..e}       # 外循环a-edo        for j in {1..5}     # 内循环1-4,结合外循环实现a1-e5共25种组合        do                username=$i$j   # 将a1-e5循环赋值给username这个变量                password=$[$RANDOM%900+100]  # 产生100-999的随机数赋值给password变量                useradd $username                echo $password | passwd --stdin $username &> /dev/null                echo "$username:$password" >> /root/.passwd        donedone


case语句

case语句为多选择语句(==其实就是类似if多分支结构==), 主要用于centos6的服务脚本里用于判断服务是start还是stop还是status等。

说明: python里没有case语句,python里用if多分支来实现. 但case语句也需要看懂结构, 不仅是shell里用,在数据库的SQL语句里也有case语句。

case语法结构

case var in               # 定义变量;var代表是变量名 pattern 1)               # 模式1;用 | 分割多个模式,相当于or      command1            # 需要执行的语句      ;;                  # 两个分号代表命令结束 pattern 2)      command2      ;; pattern 3)      command3      ;; *)                 # 不满足以上模式,默认执行*)下面的语句      command4   # 这里可以不加;;符号esac       # esac表示case语句结束

case与if多分支对比

case $sex in        if [ $sex = 男 -o $sex = man ];then 男|man )          echo "帅哥"  echo "帅哥"         elif [ $sex = 女 -o $sex = woman];then  ;;           echo "美女" 女|woman )        else   echo "美女"        echo "性别有误"  ;;          fi * )  echo "性别有误"esac

函数

通俗地说,将一组命令集合或语句形成一个整体, 给这段代码起个名字称为函数名。可以通过函数名来调用函数内的代码,达到代码重复利用的目的。

函数的定义

函数名() {  函数体(一堆命令的集合,来实现某个功能)   }function 函数名() {   函数体(一堆命令的集合,来实现某个功能)  }
function_name() {  代码  代码}function function_name() {  代码  代码}建议用第一种,不用写function,简单方便

函数的调用

直接用函数名来调用函数

funct1() {    # 函数名加()来定义函数,小括号是固定写法,大括号里面为函数体    echo 1    echo 2    echo 3    # 大括号里的三条命令就是函数主体}funct1     # 直接使用函数名字调用函数,将会执行函数主体内的内容

函数的嵌套

函数里可以调函数

funct1() {        echo 1    echo 2    echo 3}funct2() {    funct1    # funct2里调用funct1,相当于是把funct1函数主体内的内容放到这个位置    echo 4    echo 5}funct2        # 调用funct2

等同于下面的代码

funct2() {    echo 1    echo 2    echo 3    echo 4    echo 5}funct2

1555389899476


case与函数综合实例

要求:

无视系统上已有的/etc/init.d/sshd服务脚本,自己写一个服务脚本/etc/init.d/new_sshd,也能实现ssh服务的start,stop,restart,reload等功能.

知识准备与回顾

  • 服务脚本写在哪里?

需要放在/etc/init.d/目录下,并给执行权限,才能被service命令调用
  • 服务怎么启动?

大家初期太依赖于service xxx restart这样的命令服务启动三要素:1.启动命令 (如sshd服务的启动命令就是/usr/sbin/sshd;vsftpd服务的启动命令就是/usr/sbin/vsftpd)2,启动用户 (没特定指定一般就是root用户)3,启动参数 (有些服务没有启动参数,如/usr/sbin/sshd直接可启动;有些服务有启动参数,如mysqld_safe --defaults-file=/usr/local/mysql/etc/my.cnf &)
  • 服务怎么关闭?

找到pid,然后kill -15 pid关闭即可如kill -15 $(cat /var/run/sshd.pid)
  • 服务怎么reload刷新

找到pid,然后kill -1 pid即可如kill -1 $(cat /var/run/sshd.pid)
  • 服务怎么支持chkconfig开机自启动

两个条件:1, 服务脚本里要有以下这句# chkconfig: 2345 55 25第1个数字2345代表2345级别第2个数字55代表启动的顺序编号(不能超过99)第3个数字25代表关闭的顺序编号(不能超过99)2, chkconfig --add 服务名


脚本实例

[root@server ~]# vim /etc/init.d/new_sshd  # 要创建到/etc/init.d/目录下#!/bin/bash# chkconfig: 2345 64 36start() {          # start函数 /usr/sbin/sshd        # 调用/usr/sbin/sshd命令启动sshd服务}stop () {          # stop函数 kill -15 $(cat /var/run/sshd.pid)   # 通过pid文件查找pid,然后kill -15停进程}reload() {          # reload函数 kill -1 $(cat /var/run/sshd.pid)   # 通过pid文件查找pid,然后kill -1刷新}restart() {        # restart函数里面调用stop和start的函数(函数的嵌套)    stop    start}status() {          # status函数 if [ -e /var/run/sshd.pid ];then  # 通过判断pid文件是否存在,从而得知服务是否启动  echo "sshd正在运行" else  echo "sshd是停止状态" fi}case "$1" in   # $1变量回顾(shell第1天有讲),指执行脚本接的第一个参数 start )    # 如果$1的值为start,则调用start函数主体内的代码  start  ;; stop  )  stop  ;; restart )   # 如果$1的值为restart  restart  ;; reload )  reload  ;; status )  status  ;; * )     # 如果$1的值不为start,stop,restart,reload,status其中之一,则执行下面的echo语句  echo "只支持(start|stop|restart|reload|status)"esac

给执行权限,并加入chkconfig管理

# chmod 755 /etc/init.d/new_sshd # 给执行权限
# chkconfig --add new_sshd # 加入chkconfig管理

测试

先停止系统自带的sshd服务
# /etc/init.d/sshd stop # 把系统自带的sshd服务停止
# chkconfig sshd off # 把系统自带的sshd服务做成开机不自启

再测试自己写的new_sshd服务脚本
# /etc/init.d/new_sshd start # start就是对应$1
# chkconfig new_sshd on # 做成开机自动启动


正则表达式

正则表达式介绍

正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中匹配指定的字符。

几乎所有开发语言都支持正则表达式,后面学习的python语言里也有正则表达式.

linux里主要支持正则表达式的命令有 grep, sed, awk

正则一

表达式说明示例
[]括号里的字符任选其一[abc][0-9][a-z]
[^]不匹配括号里的任意字符(括号里面的^号为"非",不是开头)[^abc]表示不为a开头,b开头,c开头
^[]以括号里的任意单个字符开头(这里的^是开头的意思)^[abc]:以a或b或c开头
^[^]不以括号里的任意单个字符开头
^行的开头^root
$行的结尾bash$
^$空行

示例: 准备一个文件

# vim 1.txt
boot
boat
rat
rot
root
Root
brot.
查找有rat或rot字符的行
# grep r[oa]t 1.txt 
rat
rot
brot.
查看非r字符开头,但2-4个字符为oot的行
# grep [^r]oot 1.txt
boot
Root
查找有非大写字母与一个o字符连接的行
# grep '[^A-Z]o' 1.txt
boot
boat
rot
root 
Root # 这个也可以查出来,因为第2-3个字符符合要求
brot.
查找不以r和b开头的行
# grep ^[^rb] 1.txt
Root
查找以rot开头以rot结尾的行(也就是这一行只有rot三个字符)
# grep ^rot$ 1.txt
rot


查找.号结尾的字符,需要转义并引号引起来(比较特殊,因为下面就要讲到.号是特殊的元字符)
# grep "\."$  1.txt
brot.

问题: 使用grep输出/etc/vsftpd/vsftpd.conf配置文件里的配置(去掉注释与空行)

提示: grep -v取反
别忘了grep -E扩展模式可以实现或
如: grep -E "root|ftp" /etc/passwd

答:


正则二

表达式功能
[[:alnum:]]字母与数字字符
[[:alpha:]]字母字符(包括大小写字母)
[[:blank:]]空格与制表符
[[:digit:]]或[0-9]          (==常用==)数字
[[:lower:]]或[a-z]        (==常用==)小写字母
[[:upper:]]或[A-Z]       (==常用==)大写字母
[[:punct:]]标点符号
[[:space:]]包括换行符,回车等在内的所有空白

查找不以大写字母开头
# grep '^[^[:upper:]]' 1.txt  # 这个取反的写法很特殊,^符在两个中括号中间(了解即可)
# grep  '^[^A-Z]' 1.txt 
# grep -v '^[A-Z]' 1.txt
查找有数字的行
# grep '[0-9]' 1.txt
# grep [[:digit:]] 1.txt
查找一个数字和一个字母连起来的行
# grep -E '[0-9][a-Z]|[a-Z][0-9]' grep.txt  # grep -E是扩展模式,中间|符号代表"或者"


问题: 请问汉语描述grep [^a-z] 1.txt是查找什么?



正则三

名词解释:

元字符: 指那些在正则表达式中具有特殊意义的专用字符,如:点(.) 星(*) 问号(?)等

前导字符:即位于元字符前面的字符 ab==c==*   aoo==o==.

==注意:== 元字符如果想表达字符本身需要转义,如.号就想匹配"."号本身则需要使用\.

字符字符说明示例
*前导字符出现0次或者连续多次ab*  abbbb
.除了换行符以外,任意单个字符ab.   ab8 abu
.*任意长度的字符ab.*  abdfdfdf
{n}前导字符连续出现n次             (需要配合grep -E或egrep使用)[0-9]{3}
{n,}前导字符至少出现n次             (需要配合grep -E或egrep使用)[a-z]{4,}
{n,m}前导字符连续出现n到m次      (需要配合grep -E或egrep使用)o{2,4}
+前导字符出现1次或者多次    (需要配合grep -E或egrep使用)[0-9]+
?前导字符出现0次或者1次      (需要配合grep -E或egrep使用)go?
( )组字符

示例文本:

# vim 2.txt
ggle
gogle
google
gooogle
gagle
gaagle
gaaagle
abcgef
abcdef
goagle
aagoog
wrqsg

问题:一起来看看下面能查出哪些字符,通过结果理解记忆

# grep g.  2.txt
# grep g*  2.txt   # 结果比较怪
# grep g.g 2.txt
# grep g*g 2.txt
# grep go.g 2.txt
# grep go.*g 2.txt
# grep -E go{2}g 2.txt
# grep -E 'go{1,2}g' 2.txt # 需要引号引起来,单引双引都可以
# grep -E 'go{1,}g' 2.txt # 需要引号引起来,单引双引都可以
# grep -E go+g 2.txt
# grep -E go?g 2.txt


示例: 查出eth0网卡的IP,广播地址,子网掩码

1555429788701

# ifconfig eth0|grep Bcast| grep -E -o '([0-9]{1,3}.){3}[0-9]{1,3}'
10.1.1.11
10.1.1.255
255.255.255.0
解析:
[0-9]{1,3}\.     代表3个数字接一个.号
([0-9]{1,3}\.){3}  前面用小括号做成一个组,后面{3}代表重重复3次
[0-9]{1,3}   最后一个数字后不需要.号


示例: 匹配邮箱地址

# echo "daniel@126.com" | grep -E '^[0-9a-zA-Z]+@[a-z0-9]+\.[a-z]+$'
解析:
^[0-9a-zA-Z]+@       代表@符号前面有1个或多个字符开头(大小写字母或数字)
@[a-z0-9]+\.[a-z]+$   代表@符号和.号(注意.号要转义)中间有1个或多个字符(小写字母或数字)
 .号后面有1个或多个字符(小写字母)结尾


拓展与课后示例

perl内置正则(拓展)

Perl内置正则(需要使用grep -P来匹配),这种匹配方式在python也有。但不建议都记住,上面所学的就完全够用了.

\d      匹配数字  [0-9]
\w      匹配字母数字下划线[a-zA-Z0-9_]
\s      匹配空格、制表符、换页符[\t\r\n]


课后示例: 输入一个字符,判断输入的是大写字母还是小写字母还是数字,还是其它

方法一:
#!/bin/bash

read -n 1 -p "input a char:" char # -n 1表输入1个字符后就自动回车了
echo # echo代表换行

case "$char" in # 使用case语句对$char进程多分支判断
 [[:upper:]] ) # 正则表达式匹配大写字母,(注意:这里用[A-Z]匹配不了)
 echo "大写字母"
 ;;
 [[:lower:]] ) # 正则表达式匹配小写字母,(注意:这里用[a-z]匹配不了)
 echo "小写字母"
 ;;
 [[:digit:]] ) # 正则表达式匹配数字
 echo "数字"
 ;;
 * )
 echo "其它"
esac


方法二:
#!/bin/bash

read -n 1 -p "input a char:" char # -n 1代表输入1个字符后就自动回车了
echo # echo代表换行

# 使用if多分支进行判断
if [[ $char =~ [A-Z] ]];then # [[ ]]两个中括号里写判断条件,里面使用=~匹配正则表达式
 echo "大写字母"
elif [[ $char =~ [a-z] ]];then
 echo "小写字母"
elif [[ $char =~ [0-9] ]];then
 echo "数字"
else
 echo "其它"
fi


扫描二维码推送至手机访问

版权声明:本文由PowerShell中文社区发布,如需转载请注明出处。

本文链接:https://www.powershell.com.cn/?id=31

分享给朋友:

“shell函数与case语句-04” 的相关文章

Shell脚本介绍

Shell脚本介绍

今日目标了解Shell脚本概念磁盘相关命令回顾:磁盘相关命令说明fdisk分msdos分区与要看系统硬盘与分区情况lsblk查看块设备与其挂载情况df -h查看已经挂载的文件系统情况mount也是查看挂载的情况,还能看到挂载的参数(ro或rw等)iostat需要安装sysstat软件包,动态查看磁盘...

shell条件判断-02

shell条件判断-02

学习目标熟悉条件判断语句,如判断整数,判断字符串等熟悉流程控制语句基本语法,如if…else…#条件判断判断一个条件是为真(true)还是为假(false)判断场景##语法格式格式1: ==test==  条件表达式格式2: [ 条件表达式 ]格式3: [[ 条件表达式 ]]  ...

shell中正则表达式-05

shell中正则表达式-05

课程目标掌握常用的正则表达式元字符含义掌握sed的删除行操作掌握sed的打印行操作掌握sed的增加行操作掌握sed的修改替换操作正则表达式正则表达式介绍正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过...

shell三剑客之sed-06

shell三剑客之sed-06

学习sed的关键是要搞清楚,它是一个流==编辑器==,编辑器常见的功能有:删除行打印行增加行替换(修改)sed参数-e 进行多项编辑,即对输入行应用多条sed命令时使用-n 取消默认的输出-r 使用扩展正则表达式-i inplace,原地编辑(修改源文件)sed操作d 删除行p 打印行a 后面加行i...

Liunx定时计划任务配置说明

Liunx定时计划任务配置说明

在 Linux 中,* 代表通配符,用于表示任意值。在 cron 任务中,* 可以用来指定分钟、小时、日期等时间单位的取值。具体而言,cron 表达式由五个时间字段组成,分别表示分钟(0-59)、小时(0-23)、日期(1-31)、月份(1-12)和星期几(0-7,其中0和7都表示星期日)。这些时间...

CentOS7 服务器上使用T4显卡部署大型AI模型的详细教程

CentOS7 服务器上使用T4显卡部署大型AI模型的详细教程

环境准备服务器配置CPU:Platinum8225c 显卡T4 GPU:T4 16GB  CPU:8核 内存32GB操作系统:Centos7.6英伟达显卡驱动Docker容器环境Docker使用的NVIDIA驱动Ollama容器镜像,Ollama支持的显卡型号:点击查看查看运行环境的资源使...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。