06_SHELL编程之CASE语句+函数+正则 一、case语句关键词确认过眼神你是对的人case语句为多重匹配语句如果匹配成功执行相匹配的命令1. 语法结构说明pattern表示需要匹配的模式 casevarin 定义变量;var代表是变量名 pattern 1)模式1;用|分割多个模式相当于or command1 需要执行的语句;;两个分号代表命令结束 pattern 2)command2;;pattern 3)command3;;*)default不满足以上模式默认执行*)下面的语句 command4;;esac esac表示case语句结束2. 应用案例㈠ 脚本传不同值做不同事具体需求当给程序传入start、stop、restart三个不同参数时分别执行相应命令#!/bin/env bashcase$1instart|S)service apachestart/dev/null echoapache 启动成功;;stop|T)service apache stop /dev/null echoapache 停止成功;;restart|R)service apache restart /dev/null echoapache 重启完毕;;*)echo请输入要做的事情...;;esac㈡ 根据用户需求选择做事具体需求脚本提示让用户输入需要管理的服务名然后提示用户需要对服务做什么操作如启动关闭等操作#!/bin/env bashread-p请输入你要管理的服务名称(vsftpd):service case$servicein vsftpd|ftp)read-p请选择你需要做的事情(restart|stop):action case$actionin stop|S)service vsftpd stop /dev/null echo该$serivce服务已经停止成功;;start)service vsftpdstart/dev/null echo该$serivce服务已经成功启动;;esac;;httpd|apache)echoapache hello world;;*)echo请输入你要管理的服务名称(vsftpd);;esac㈢ 菜单提示让用户选择需要做的事具体需求模拟一个多任务维护界面;当执行程序时先显示总菜单然后进行选择后做相应维护监控操作**********请选择*********h 显示命令帮助 f 显示磁盘分区 d 显示磁盘挂载 m 查看内存使用 u 查看系统负载 q 退出程序*************************思路菜单打印出来交互式让用户输入操作编号然后做出相应处理落地实现菜单打印(分解动作)#!/bin/env bashcat-EOF h 显示命令帮助 f 显示磁盘分区 d 显示磁盘挂载 m 查看内存使用 u 查看系统负载 q 退出程序 EOF最终实现#!/bin/bash#打印菜单cat-EOF h 显示命令帮助 f 显示磁盘分区 d 显示磁盘挂载 m 查看内存使用 u 查看系统负载 q 退出程序 EOF#让用户输入需要的操作whiletruedoread-p请输入需要操作的选项[f|d]:var1 case$var1in h)cat-EOF h 显示命令帮助 f 显示磁盘分区 d 显示磁盘挂载 m 查看内存使用 u 查看系统负载 q 退出程序 EOF;;f)fdisk-l;;d)df-h;;m)free-m;;u)uptime;;q)exit;;esac done#!/bin/bash#打印菜单menu(){cat-ENDh 显示命令帮助 f 显示磁盘分区 d 显示磁盘挂载 m 查看内存使用 u 查看系统负载 q 退出程序END}menuwhiletruedoread-p请输入你的操作[h for help]:var1 case$var1in h)menu;;f)read-p请输入你要查看的设备名字[/dev/sdb]:var2 case$var2in/dev/sda)fdisk-l/dev/sda;;/dev/sdb)fdisk-l/dev/sdb;;esac;;d)lsblk;;m)free-m;;u)uptime;;q)exit;;esac done练习输入一个等级A-E查看每个等级的成绩如输入A则显示“90分~100分”依次类推判断用户输入的字符串如果是hello,则显示world如果是world,则显示hello,否则提示请输入hello或者world谢谢二、函数1. 什么是函数shell中允许将一组命令集合或语句形成一段可用代码这些代码块称为shell函数给这段代码起个名字称为函数名后续可以直接调用该段代码的功能2. 如何定义函数方法1函数名(){函数体一堆命令的集合来实现某个功能}方法2function函数名(){函数体一堆命令的集合来实现某个功能echohelloechoworld}函数中return说明:return可以结束一个函数。类似于循环控制语句break(结束当前循环执行循环体后面的代码)。return默认返回函数中最后一个命令状态值也可以给定参数值范围是0-256之间。如果没有return命令函数将返回最后一个指令的退出状态值。##3. 函数如何调用㈠ 当前命令行调用[rootMissHou shell04]# cat fun1.sh#!/bin/bashhello(){echohello lilei$1hostname}menu(){cat-EOF 1.mysql 2.web 3.app 4.exitEOF}[rootMissHou shell04]# source fun1.sh[rootMissHou shell04]# . fun1.sh[rootMissHou shell04]# hello 888hello lilei 888 MissHou.itcast.cc[rootMissHou shell04]# menu1.mysql 2.web 3.app 4.exit㈡ 定义到用户的环境变量中[rootMissHou shell05]# vim ~/.bashrc文件中增加如下内容 hello(){echohello lilei$1hostname}menu(){cat-EOF 1.mysql 2.web 3.app 4.exitEOF}注意 当用户打开bash的时候会读取该文件㈢ 脚本中调用#!/bin/bash#打印菜单source./fun1.sh menu(){cat-ENDh 显示命令帮助 f 显示磁盘分区 d 显示磁盘挂载 m 查看内存使用 u 查看系统负载 q 退出程序END}menu//调用函数4. 应用案例具体需求写一个脚本收集用户输入的基本信息(姓名性别年龄)如不输入一直提示输入最后根据用户的信息输出相对应的内容思路交互式定义多个变量来保存用户信息 姓名、性别、年龄如果不输一直提示输入循环直到输入字符串不为空 while 判断输入字符串是否为空每个信息都必须不能为空该功能可以定义为一个函数方便下面脚本调用根据用户输入信息做出匹配判断代码实现#!/bin/bash#该函数实现用户如果不输入内容则一直循环直到用户输入为止并且将用户输入的内容打印出来input_fun(){input_varoutput_var$1while[-z$input_var]doread-p$output_varinput_var doneecho$input_var}input_fun 请输入你的姓名: 或者#!/bin/bashfun(){read-p$1varif[-z$var];then fun$1elseecho$varfi}#调用函数并且获取用户的姓名、性别、年龄分别赋值给name、sex、age变量name$(input_fun 请输入你的姓名:)sex$(input_fun 请输入你的性别:)age$(input_fun 请输入你的年龄:)#根据用户输入的性别进行匹配判断case$sexin man)if[$age-gt18-a$age-le35];thenecho中年大叔你油腻了吗加油elif[$age-gt35];thenecho保温杯里泡枸杞elseecho年轻有为。。。fi;;woman)xxx;;*)xxx;;esac扩展延伸描述以下代码含义 :(){:|:}:三、综合案例1. 任务背景现有的跳板机虽然实现了统一入口来访问生产服务器yunwei用户权限太大可以操作跳板机上的所有目录文件存在数据被误删的安全隐患所以希望你做一些安全策略来保证跳板机的正常使用。2. 具体要求只允许yunwei用户通过跳板机远程连接后台的应用服务器做一些维护操作公司运维人员远程通过yunwei用户连接跳板机时跳出以下菜单供选择欢迎使用Jumper-server请选择你要操作的主机 1.DB1-Master 2.DB2-Slave 3.Web1 4.Web2 h.help q.exit当用户选择相应主机后直接免密码登录成功如果用户不输入一直提示用户输入直到用户选择退出3. 综合分析将脚本放到yunwei用户家目录里的.bashrc文件里/shell05/jumper-server.sh将菜单定义为一个函数[打印菜单]方便后面调用用case语句来实现用户的选择【交互式定义变量】当用户选择了某一台服务器后进一步询问用户需要做的事情 case…esac 交互式定义变量使用循环来实现用户不选择一直让其选择限制用户退出后直接关闭终端 exit4. 落地实现#!/bin/bash# jumper-server# 定义菜单打印功能的函数menu(){cat-EOF 欢迎使用Jumper-server请选择你要操作的主机 1.DB1-Master 2.DB2-Slave 3.Web1 4.Web2 h.help q.exitEOF}# 屏蔽以下信号trap1 2 3 19# 调用函数来打印菜单menu#循环等待用户选择whiletruedo# 菜单选择case...esac语句read-p请选择你要访问的主机:host case$hostin 1)ssh root10.1.1.1;;2)ssh root10.1.1.2;;3)ssh root10.1.1.3;;h)clear;menu;;q)exit;;esac done 将脚本放到yunwei用户家目录里的.bashrc里执行 bash ~/jumper-server.shexit进一步完善需求为了进一步增强跳板机的安全性工作人员通过跳板机访问生产环境但是不能在跳板机上停留。#!/bin/bash#公钥推送成功trap1 2 3 19#打印菜单用户选择menu(){cat-EOF 欢迎使用Jumper-server请选择你要操作的主机 1.DB1-Master 2.DB2-Slave 3.Web1 4.Web2 h.help q.exitEOF}#调用函数来打印菜单menuwhiletruedoread-p请输入你要选择的主机[h for help]host#通过case语句来匹配用户所输入的主机case$hostin 1|DB1)ssh root10.1.1.1;;2|DB2)ssh root10.1.1.2;;3|web1)ssh root10.1.1.250;;h|help)clear;menu;;q|quit)exit;;esac done 自己完善功能 1.用户选择主机后需要事先推送公钥如何判断公钥是否已推 2.比如选择web1时再次提示需要做的操作比如 clean log 重启服务kill某个进程回顾信号1)SIGHUP 重新加载配置 2)SIGINT 键盘中断^C 3)SIGQUIT 键盘退出 9)SIGKILL 强制终止 15)SIGTERM 终止正常结束缺省信号 18)SIGCONT 继续 19)SIGSTOP 停止 20)SIGTSTP 暂停^Z四、正则表达式1. 正则表达式是什么正则表达式Regular Expression、regex或regexp缩写为RE也译为正规表示法、常规表示法是一种字符模式用于在查找过程中匹配指定的字符。许多程序设计语言都支持利用正则表达式进行字符串操作。例如在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件例如sed和grep普及开的。支持正则表达式的程序如locate |find| vim| grep| sed |awk2. 正则能干什么匹配邮箱、匹配身份证号码、手机号、银行卡号等匹配某些特定字符串做特定处理等等3. 正则当中名词解释元字符指那些在正则表达式中具有特殊意义的专用字符,如:点(.) 星(*) 问号(?)等前导字符位于元字符前面的字符. ab**c*** aoo**o.**4. 第一类正则表达式㈠ 正则中普通常用的元字符元字符功能备注.匹配除了换行符以外的任意单个字符*前导字符出现0次或连续多次.*任意长度字符ab.*^行首(以…开头)^root$行尾(以…结尾)bash$^$空行[]匹配括号里任意单个字符或一组单个字符[abc][^]匹配不包含括号里任一单个字符或一组单个字符[^abc]^[]匹配以括号里任意单个字符或一组单个字符开头^[abc][]匹配不以括号里任意单个字符或一组单个字符开头[abc]示例文本# cat 1.txtggle gogle google gooogle goooooogle gooooooogle taobao.com taotaobaobao.com jingdong.com dingdingdongdong.com 10.1.1.1 Adfjd8789JHfdsdf/ a87fdjfkdLKJK 7kdjfd989KJK;bSKJjkksdjf878.cidufKJHJ6576,hello world helloworld yourself举例说明㈡ 正则中其他常用元字符元字符功能备注\取单词的头\取单词的尾\ \精确匹配\{n\}匹配前导字符连续出现n次\{n,\}匹配前导字符至少出现n次\{n,m\}匹配前导字符出现n次与m次之间\( \)保存被匹配的字符\d匹配数字grep -P[0-9]\w匹配字母数字下划线grep -P[a-zA-Z0-9_]\s匹配空格、制表符、换页符grep -P[\t\r\n]举例说明需求将10.1.1.1替换成10.1.1.254 1vim编辑器支持正则表达式# vim 1.txt:%s#\(10.1.1\).1#\1.254#g:%s/\(10.1.1\).1/\1.254/g 2sed支持正则表达式【后面学】# sed -n s#\(10.1.1\).1#\1.254#p 1.txt10.1.1.254 说明 找出含有10.1.1的行同时保留10.1.1并标记为标签1之后可以使用\1来引用它。 最多可以定义9个标签从左边开始编号最左边的是第一个。 需求将helloworld yourself 换成hellolilei myself# vim 1.txt:%s#\(hello\)world your\(self\)#\1lilei my\2#g# sed -n s/\(hello\)world your\(self\)/\1lilei my\2/p 1.txthellolilei myself# sed -n s/helloworld yourself/hellolilei myself/p 1.txthellolilei myself# sed -n s/\(hello\)world your\(self\)/\1lilei my\2/p 1.txthellolilei myself Perl内置正则 \d 匹配数字[0-9]\w 匹配字母数字下划线[a-zA-Z0-9_]\s 匹配空格、制表符、换页符[\t\r\n]# grep -P \d 1.txt# grep -P \w 2.txt# grep -P \s 3.txt㈢ 扩展类正则常用元字符丑话说在前面我说我比较特殊你要相信否则我错给你看grep你要用我必须加-E或者 让你兄弟egrep来找我sed你要用我必须加-r扩展元字符功能备注匹配一个或多个前导字符bo 匹配boo、 bo?匹配零个或一个前导字符bo? 匹配b、 bo|或匹配a或b()组字符看成整体(my|your)self表示匹配myself或匹配yourself{n}前导字符重复n次{n,}前导字符重复至少n次{n,m}前导字符重复n到m次举例说明# grep root|ftp|adm /etc/passwd# egrep root|ftp|adm /etc/passwd# grep -E root|ftp|adm /etc/passwd# grep -E ogle test.txt# grep -E o?gle test.txt# egrep go{2,} 1.txt# egrep (my|your)self 1.txt使用正则过滤出文件中的IP地址# grep [0-9]\{2\}\.[0-9]\{1\}\.[0-9]\{1\}\.[0-9]\{1\} 1.txt10.1.1.1# grep [0-9]{2}\.[0-9]{1}\.[0-9]{1}\.[0-9]{1} 1.txt# grep -E [0-9]{2}\.[0-9]{1}\.[0-9]{1}\.[0-9]{1} 1.txt10.1.1.1# grep -E [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} 1.txt10.1.1.1# grep -E ([0-9]{1,3}\.){3}[0-9]{1,3} 1.txt10.1.1.15. 第二类正则表达式功能示例[:alnum:]字母与数字字符[[:alnum:]][:alpha:]字母字符(包括大小写字母)[[:alpha:]]{4}[:blank:]空格与制表符[[:blank:]]*[:digit:]数字[[:digit:]]?[:lower:]小写字母[[:lower:]]{4,}[:upper:]大写字母[[:upper:]][:punct:]标点符号[[:punct:]][:space:]包括换行符回车等在内的所有空白[[:space:]][rootserver shell05]# grep -E ^[[:digit:]] 1.txt[rootserver shell05]# grep -E ^[^[:digit:]] 1.txt[rootserver shell05]# grep -E [[:lower:]]{4,} 1.txt6. 正则表达式总结把握一个原则让你轻松搞定可恶的正则符号我要找什么找数字 [0-9]找字母 [a-zA-Z]找标点符号 [[:punct:]]我要如何找看心情找以什么为首 ^key以什么结尾 key$包含什么或不包含什么 [abc] ^[abc] [^abc][abc]我要找多少呀找前导字符出现0次或连续多次 ab*找任意单个(一次)字符 ab.找任意字符 ab.*找前导字符连续出现几次 {n} {n,m} {n,}找前导字符出现1次或多次 go找前到字符出现0次或1次 go?五、正则元字符一栏表元字符在正则中具有特殊意义的专用字符如: 星号(*)、加号()等前导字符元字符前面的字符叫前导字符元字符功能示例*前导字符出现0次或者连续多次ab* abbbb.除了换行符以外任意单个字符ab. ab8 abu.*任意长度的字符ab.* adfdfdf[]括号里的任意单个字符或一组单个字符[abc][0-9][a-z][^]不匹配括号里的任意单个字符或一组单个字符[^abc]^[]匹配以括号里的任意单个字符开头^[abc][]不匹配以括号里的任意单个字符开头^行的开头^root$行的结尾bash$^$空行\{n\}和{n}前导字符连续出现n次[0-9]\{3\}\{n,\}和{n,}前导字符至少出现n次[a-z]{4,}\{n,m\}和{n,m}前导字符连续出现n-m次go{2,4}\\精确匹配单词\hello\\(\)保留匹配到的字符\(hello\)前导字符出现1次或者多次[0-9]?前导字符出现0次或者1次go?|或root|ftp()组字符(hello|world)123\dperl内置正则grep -P \d\w匹配字母数字下划线六、正则练习1. 文件准备# vim test.txtAieur45869Root0000 9h847RkjfkIIIhello rootHllow88000dfjj 8ikuioerhfhupliooking hello world 192.168.0.254 welcome to uplooking.abcderfkdjfkdtest rlllA899kdfkdfj iiiA848890ldkfjdkfj abc 12345678908374 123456qq.com 123456163.com abcdefgitcast.com23ed2. 具体要求1、查找不以大写字母开头的行三种写法。 grep^[^A-Z]2.txt grep-v^[A-Z]2.txt grep^[^[:upper:]]2.txt 2、查找有数字的行两种写法 grep[0-9]2.txt grep-P\d2.txt 3、查找一个数字和一个字母连起来的 grep-E[0-9][a-zA-Z]|[a-zA-Z][0-9]2.txt 4、查找不以r开头的行 grep-v^r2.txt grep^[^r]2.txt 5、查找以数字开头的 grep^[0-9]2.txt 6、查找以大写字母开头的 grep^[A-Z]2.txt 7、查找以小写字母开头的 grep^[a-z]2.txt 8、查找以点结束的 grep\.$2.txt 9、去掉空行 grep-v^$2.txt 10、查找完全匹配abc的行 grep\abc\2.txt 11、查找A后有三个数字的行 grep-EA[0-9]{3}2.txt grepA[0-9]\{3\}2.txt 12、统计root在/etc/passwd里出现了几次 grep-oroot1.txt|wc-l 13、用正则表达式找出自己的IP地址、广播地址、子网掩码 ifconfig eth0|grep Bcast|grep-o[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}ifconfig eth0|grep Bcast|grep-E-o([0-9]{1,3}.){3}[0-9]{1,3}ifconfig eth0|grep Bcast|grep-P-o\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}ifconfig eth0|grep Bcast|grep-P-o(\d{1,3}.){3}\d{1,3}ifconfig eth0|grep Bcast|grep-P-o(\d.){3}\d# egrep --color [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} /etc/sysconfig/network-scripts/ifcfg-eth0IPADDR10.1.1.1 NETMASK255.255.255.0 GATEWAY10.1.1.254# egrep --color [[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3} /etc/sysconfig/network-scripts/ifcfg-eth0IPADDR10.1.1.1 NETMASK255.255.255.0 GATEWAY10.1.1.254 14、找出文件中的ip地址并且打印替换成172.16.2.254 grep-o-E([0-9]{1,3}\.){3}[0-9]{1,3}1.txt|sed-ns/192.168.0.\(254\)/172.16.2.\1/p15、找出文件中的ip地址 grep-o-E([0-9]{1,3}\.){3}[0-9]{1,3}1.txt 16、找出全部是数字的行 grep-E^[0-9]$test 17、找出邮箱地址 grep-E^[0-9][a-z0-9]\.[a-z]$grep--help: 匹配模式选择 Regexp selection and interpretation:-E,--extended-regexp 扩展正则-G,--basic-regexp 基本正则-P,--perl-regexp 调用perl的正则-e,--regexpPATTERN use PATTERNformatching-f,--fileFILE obtain PATTERNfromFILE-i,--ignore-case 忽略大小写-w,--word-regexp 匹配整个单词七、练习2脚本搭建web服务要求如下用户输入web服务器的IP、域名以及数据根目录如果用户不输入则一直提示输入直到输入为止当访问www.test.cc时可以访问到数据根目录里的首页文件“this is test page”参考脚本参考#!/bin/bashconf/etc/httpd/conf/httpd.conf input_fun(){input_varoutput_var$1while[-z$input_var]doread-p$output_varinput_var doneecho$input_var}ipaddr$(input_funInput Host ip[192.168.0.1]:)web_host_name$(input_funInput VirtualHostName [www.test.cc]:)root_dir$(input_funInput host Documentroot dir:[/var/www/html]:)[!-d$root_dir] mkdir-p$root_dirchown apache.apache$root_dir chmod 755$root_direchothis is$web_host_name$root_dir/index.htmlecho$ipaddr$web_host_name/etc/hosts[-f$conf]cat$confendNameVirtualHost$ipaddr:80 VirtualHost$ipaddr:80 ServerAdmin webmaster$web_host_nameDocumentRoot$root_dirServerName$web_host_nameErrorLog logs/$web_host_name-error_log CustomLog logs/$web_host_name-access_loh common /VirtualHostend