当前位置: 首页 > news >正文

shell编程之循环语句


typora-copy-images-to: pictures
typora-root-url: …\pictures

文章目录

    • typora-copy-images-to: pictures typora-root-url: ..\..\pictures
  • 一、for循环语句
    • 1. for循环语法结构
      • ㈠ ==列表==循环
      • ㈡ 不带列表循环
      • ㈢ 类C风格的for循环
    • 2. 应用案例
      • ㈠ 脚本==计算==1-100奇数和
        • ① 思路
        • ② 落地实现(条条大路通罗马)
        • ③ 循环控制语句
      • ㈡ 判断所输整数是否为质数
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户
        • ① 思路
        • ② 落地实现
    • 3. 课堂练习
      • ㈠ 批量创建用户
      • ㈡ 局域网内脚本检查主机网络通讯
      • ㈢ 判断闰年
    • 2. 应用案例
      • ㈠ 脚本计算1-50偶数和
      • ㈡ 脚本同步系统时间
        • ① 具体需求
        • ② 思路
        • ③ 落地实现
    • 1. until语法结构
    • 2. 应用案例
      • ㈡ 思路
      • ㈢ 落地实现
  • 四、课后作业
    • typora-copy-images-to: pictures typora-root-url: ..\..\pictures
  • 一、==for循环语句==
    • 1. for循环语法结构
      • ㈠ ==列表==循环
      • ㈡ 不带列表循环
      • ㈢ 类C风格的for循环
    • 2. 应用案例
      • ㈠ 脚本==计算==1-100奇数和
        • ① 思路
        • ② 落地实现(条条大路通罗马)
        • ③ 循环控制语句
      • ㈡ 判断所输整数是否为质数
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户
        • ① 思路
        • ② 落地实现
    • 3. 课堂练习
      • ㈠ 批量创建用户
      • ㈡ 局域网内脚本检查主机网络通讯
      • ㈢ 判断闰年
    • 2. 应用案例
      • ㈠ 脚本计算1-50偶数和
      • ㈡ 脚本同步系统时间
        • ① 具体需求
        • ② 思路
        • ③ 落地实现
    • 1. until语法结构
    • 2. 应用案例
      • ㈡ 思路
      • ㈢ 落地实现
  • 四、课后作业
  • 一、随机数
    • 1. 如何生成随机数?
    • 2. 实战案例
      • ㈠ 随机产生以139开头的电话号码
        • ① 思路
        • ② 落地实现
      • ㈡ 随机抽出5位幸运观众
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户(密码随机产生)
        • ① 思路
        • ② 落地实现
  • 二、嵌套循环
      • ㈠ 打印指定图案
      • ㈡ 落地实现1
      • ㈢ 落地实现2
  • 三、阶段性补充总结
    • 1、变量定义
    • 2. 流程控制语句
    • 3. 循环语句
    • 4. 影响shell程序的内置命令
      • ㈠ 具体需求
      • ㈢ 落地实现
        • ② 最终实现
  • 一、case语句
    • 1. 语法结构
    • 2. 应用案例
      • ㈠ 脚本传不同值做不同事
      • ㈡ 根据用户需求选择做事
  • 二、==函数==
    • 1. 什么是函数?
    • 2. 如何定义函数?
      • ㈠ 当前命令行调用
      • ㈡ 定义到用户的环境变量中
      • ㈢ 脚本中调用
    • 1. 任务背景
    • 2. 具体要求
    • 3. 综合分析
    • 4. 落地实现
  • 四、正则表达式
    • 2. 正则能干什么?
    • 3. 正则当中名词解释
      • ㈠ 正则中普通常用的元字符
      • ㈡ 正则中其他常用元字符
      • ㈢ 扩展类正则常用元字符
    • 6. 正则表达式总结
  • 五、正则元字符一栏表
  • 六、正则练习作业
    • 1. 文件准备
    • 2. 具体要求
    • 脚本搭建web服务

#本机课程目标

  • 掌握for循环语句的基本语法结构
  • 掌握while和until循环语句的基本语法结构

一、for循环语句

关键词:爱的魔力转圈圈😇

1. for循环语法结构

列表循环

列表for循环:用于将一组命令执行**已知的次数**

  • 基本语法格式
for variable in {list}docommand command…done
或者
for variable in a b cdocommandcommanddone
  • 举例说明
# for var in {1..10};do echo $var;done
# for var in 1 2 3 4 5;do echo $var;done
# for var in `seq 10`;do echo $var;done
# for var in $(seq 10);do echo $var;done
# for var in {0..10..2};do echo $var;done
# for var in {2..10..2};do echo $var;done
# for var in {10..1};do echo $var;done
# for var in {10..1..-2};do echo $var;done
# for var in `seq 10 -2 1`;do echo $var;done

㈡ 不带列表循环

不带列表的for循环执行时由用户指定参数和参数的个数

  • 基本语法格式
for variabledocommand command…done
  • 举例说明
#!/bin/bash
for var
do
echo $var
doneecho "脚本后面有$#个参数"

㈢ 类C风格的for循环

  • 基本语法结构
for(( expr1;expr2;expr3 ))docommandcommand…done
for (( i=1;i<=5;i++))doecho $idoneexpr1:定义变量并赋初值
expr2:决定是否进行循环(条件)
expr3:决定循环变量如何改变,决定循环什么时候退出
  • 举例说明
 # for ((i=1;i<=5;i++));do echo $i;done# for ((i=1;i<=10;i+=2));do echo $i;done# for ((i=2;i<=10;i+=2));do echo $i;done

2. 应用案例

㈠ 脚本计算1-100奇数和

① 思路

  1. 定义一个变量来保存奇数的和 sum=0
  2. 找出1-100的奇数,保存到另一个变量里 i=遍历出来的奇数
  3. 从1-100中找出奇数后,再相加,然后将和赋值给变量 循环变量 for
  4. 遍历完毕后,将sum的值打印出来

② 落地实现(条条大路通罗马)

#!/bin/env bash
# 计算1-100的奇数和
# 定义变量来保存奇数和
sum=0#for循环遍历1-100的奇数,并且相加,把结果重新赋值给sumfor i in {1..100..2}
dolet sum=$sum+$i
done
#打印所有奇数的和
echo "1-100的奇数和是:$sum"方法1:
#!/bin/bash
sum=0
for i in {1..100..2}
dosum=$[$i+$sum]
done
echo "1-100的奇数和为:$sum"方法2:
#!/bin/bash
sum=0
for ((i=1;i<=100;i+=2))
dolet sum=$i+$sum
done
echo "1-100的奇数和为:$sum"方法3:
#!/bin/bash
sum=0
for ((i=1;i<=100;i++))
doif [ $[$i%2] -ne 0 ];thenlet sum=$sum+$ifi
或者
test $[$i%2] -ne 0 && let sum=$sum+$idone
echo "1-100的奇数和为:$sum"方法4:
sum=0
for ((i=1;i<=100;i++))
doif [ $[$i%2] -eq 0 ];thencontinueelselet sum=$sum+$ifi
done
echo "1-100的奇数和为:$sum"#!/bin/bash
sum=0
for ((i=1;i<=100;i++))
dotest $[$i%2] -eq 0 && continue || let sum=sum+$i
done
echo "1-100的奇数和是:$sum"

③ 循环控制语句

循环体: do…done之间的内容

  • continue:继续;表示循环体内下面的代码不执行,重新开始下一次循环
  • break:打断;马上停止执行本次循环,执行循环体后面的代码
  • exit:表示直接跳出程序
[root@server ~]# cat for5.sh 
#!/bin/bash
for i in {1..5}
dotest $i -eq 2 && break || touch /tmp/file$i
done
echo hello hahahah

㈡ 判断所输整数是否为质数

**质数(素数):**只能被1和它本身整除的数叫质数。
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

① 思路

  1. 让用户输入一个数,保存到一个变量里
  2. 如果能被其他数整除就不是质数——>$num%$i 是否等于0 $i=2到​$num-1
  3. 如果输入的数是1或者2取模根据上面判断又不符合,所以先排除1和2
  4. 测试序列从2开始,输入的数是4——>得出结果$num不能和$i相等,并且$num不能小于$i

② 落地实现

#!/bin/bash
read -p "请输入一个正整数字:" number[ $number -eq 1 ] && echo "$number不是质数" && exit
[ $number -eq 2 ] && echo "$number是质数" && exitfor i in `seq 2 $[$number-1]`do[ $[$number%$i] -eq 0 ] && echo "$number不是质数" && exitdone
echo "$number是质数" && exit

㈢ 批量创建用户

**需求:**批量加5个新用户,以u1到u5命名,并统一加一个新组,组名为class,统一改密码为123

① 思路

  1. 添加用户的命令
  2. 判断class组是否存在
  3. 根据题意,判断该脚本循环5次来添加用户
  4. 给用户设置密码,应该放到循环体里面

② 落地实现

方法一:
#!/bin/bash
#判断class组是否存在
grep -w class /etc/group &>/dev/null
[ $? -ne 0 ] && groupadd class
#批量创建5个用户
for i in {1..5}
douseradd -G class u$iecho 123|passwd --stdin u$i
done方法二:
#!/bin/bash
#判断class组是否存在
cut -d: -f1 /etc/group|grep -w class &>/dev/null
[ $? -ne 0 ] && groupadd class#循环增加用户,循环次数5次,for循环,给用户设定密码
for ((i=1;i<=5;i++))
douseradd u$i -G classecho 123|passwd --stdin u$i
done方法三:
#!/bin/bash
grep -w class /etc/group &>/dev/null
test $? -ne 0 && groupadd class
或者
groupadd class &>/dev/nullfor ((i=1;i<=5;i++))
do
useradd -G class u$i && echo 123|passwd --stdin u$i
done

3. 课堂练习

㈠ 批量创建用户

**需求1:**批量新建5个用户stu1~stu5,要求这几个用户的家目录都在/rhome.

#!/bin/bash
#判断/rhome是否存在
[ -f /rhome ] && mv /rhome /rhome.bak
test ! -f /rhome -a ! -d /rhome && mkdir /rhome
或者
[ -f /rhome ] && mv /rhome /rhome.bak || [ ! -d /rhome ] && mkdir /rhome 
#创建用户,循环5次
for ((i=1;i<=5;i++))
douseradd -d /rhome/stu$i stu$iecho 123|passwd --stdin stu$i
done

㈡ 局域网内脚本检查主机网络通讯

需求2:

写一个脚本,局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里

以10.1.1.1~10.1.1.10为例

#!/bin/bash
#定义变量
ip=10.1.1
#循环去ping主机的IP
for ((i=1;i<=10;i++))
doping -c1 $ip.$i &>/dev/nullif [ $? -eq 0 ];thenecho "$ip.$i is ok" >> /tmp/ip_up.txtelseecho "$ip.$i is down" >> /tmp/ip_down.txtfi或者[ $? -eq 0 ] && echo "$ip.$i is ok" >> /tmp/ip_up.txt || echo "$ip.$i is down" >> /tmp/ip_down.txt
done[root@server shell03]# time ./ping.sh         real    0m24.129s
user    0m0.006s
sys     0m0.005s

延伸扩展:shell脚本并发

并行执行:
{程序}&表示将程序放到后台并行执行,如果需要等待程序执行完毕再进行下面内容,需要加wait#!/bin/bash
#定义变量
ip=10.1.1
#循环去ping主机的IP
for ((i=1;i<=10;i++))
do
{ping -c1 $ip.$i &>/dev/nullif [ $? -eq 0 ];thenecho "$ip.$i is ok" >> /tmp/ip_up.txtelseecho "$ip.$i is down" >> /tmp/ip_down.txtfi
}&
done
wait
echo "ip is ok...."[root@server ~]# time ./ping.sh 
ip is ok...real    0m3.091s
user    0m0.001s
sys     0m0.008s

㈢ 判断闰年

需求3:

输入一个年份,判断是否是润年(能被4整除但不能被100整除,或能被400整除的年份即为闰年)

#!/bin/bash
read -p "Please input year:(2017)" year
if [ $[$year%4] -eq 0 -a $[$year%100] -ne 0 ];thenecho "$year is leap year"
elif [ $[$year%400] -eq 0 ];thenecho "$year is leap year"
elseecho "$year is not leap year"
fi

##4. 总结

  • FOR循环语法结构
  • FOR循环可以结合条件判断和流程控制语句
    • do …done 循环体
    • 循环体里可以是命令集合,再加上条件判断以及流程控制
  • 控制循环语句
    • continue 继续,跳过本次循环,继续下一次循环
    • break 打断,跳出循环,执行循环体外的代码
    • exit 退出,直接退出程序

#二、while循环语句

特点:条件为真就进入循环;条件为假就退出循环

##1. while循环语法结构

while 表达式docommand...donewhile  [ 1 -eq 1 ] 或者 (( 1 > 2 ))docommandcommand...done

循环打印1-5数字

FOR循环打印:
for ((i=1;i<=5;i++))
doecho $i
donewhile循环打印:
i=1
while [ $i -le 5 ]
doecho $ilet i++
done

2. 应用案例

㈠ 脚本计算1-50偶数和

#!/bin/bash
#定义变量
sum=0
i=2
#循环打印1-50的偶数和并且计算后重新赋值给sum
while [ $i -le 50 ]
dolet sum=sum+ilet i+=2
done
#打印sum的值
echo "1-50的偶数和为:$sum"

㈡ 脚本同步系统时间

① 具体需求

  1. 写一个脚本,30秒同步一次系统时间,时间同步服务器10.1.1.1
  2. 如果同步失败,则进行邮件报警,每次失败都报警
  3. 同步成功,也进行邮件通知,但是成功100次才通知一次

② 思路

  1. 每个30s同步一次时间,该脚本是一个死循环

  2. 同步失败发送邮件

  3. 同步成功100次发送邮件

③ 落地实现

#!/bin/bash
#定义变量
count=0
ntp_server=10.1.1.1
while true
dordate -s $ntp-server &>/dev/nullif [ $? -ne 0 ];thenecho "system date failed" |mail -s 'check system date'  root@localhost	elselet count++if [ $[$count%100] -eq 0 ];thenecho "system date successfull" |mail -s 'check system date'  root@localhost && count=0fifi
sleep 3
done以上脚本还有更多的写法,课后自己完成

#三、until循环

特点条件为假就进入循环;条件为真就退出循环

1. until语法结构

until expression   [ 1 -eq 1 ]  (( 1 >= 1 ))docommandcommand...done

打印1-5数字

i=1
while [ $i -le 5 ]
doecho $ilet i++
donei=1
until [ $i -gt 5 ]
doecho $ilet i++
done

2. 应用案例

###㈠ 具体需求

  1. 使用until语句批量创建10个用户,要求stu1—stu5用户的UID分别为1001—1005;
  2. stu6~stu10用户的家目录分别在/rhome/stu6—/rhome/stu10

㈡ 思路

㈢ 落地实现

#!/bin/bash
i=1
until [ $i -gt 10 ]
doif [ $i -le 5 ];thenuseradd -u $[1000+$i] stu$i && echo 123|passwd --stdin stu$ielse[ ! -d /rhome ] && mkdir /rhomeuseradd -d /rhome/stu$i stu$i && echo 123|passwd --stdin stu$i		fi
let i++
done

四、课后作业

  1. 判断/tmp/run目录是否存在,如果不存在就建立,如果存在就删除目录里所有文件
  2. 输入一个路径,判断路径是否存在,而且输出是文件还是目录,如果是链接文件,还得输出是 有效的连接还是无效的连接
  3. 交互模式要求输入一个ip,然后脚本判断这个IP 对应的主机是否 能ping 通,输出结果类似于:
    Server 10.1.1.20 is Down! 最后要求把结果邮件到本地管理员root@localhost mail01@localhost
  4. 写一个脚本/home/program,要求当给脚本输入参数hello时,脚本返回world,给脚本输入参数world时,脚本返回hello。而脚本没有参数或者参数错误时,屏幕上输出“usage:/home/program hello or world”
  5. 写一个脚本自动搭建nfs服务

typora-copy-images-to: pictures
typora-root-url: …\pictures

文章目录

    • typora-copy-images-to: pictures typora-root-url: ..\..\pictures
  • 一、for循环语句
    • 1. for循环语法结构
      • ㈠ ==列表==循环
      • ㈡ 不带列表循环
      • ㈢ 类C风格的for循环
    • 2. 应用案例
      • ㈠ 脚本==计算==1-100奇数和
        • ① 思路
        • ② 落地实现(条条大路通罗马)
        • ③ 循环控制语句
      • ㈡ 判断所输整数是否为质数
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户
        • ① 思路
        • ② 落地实现
    • 3. 课堂练习
      • ㈠ 批量创建用户
      • ㈡ 局域网内脚本检查主机网络通讯
      • ㈢ 判断闰年
    • 2. 应用案例
      • ㈠ 脚本计算1-50偶数和
      • ㈡ 脚本同步系统时间
        • ① 具体需求
        • ② 思路
        • ③ 落地实现
    • 1. until语法结构
    • 2. 应用案例
      • ㈡ 思路
      • ㈢ 落地实现
  • 四、课后作业
    • typora-copy-images-to: pictures typora-root-url: ..\..\pictures
  • 一、==for循环语句==
    • 1. for循环语法结构
      • ㈠ ==列表==循环
      • ㈡ 不带列表循环
      • ㈢ 类C风格的for循环
    • 2. 应用案例
      • ㈠ 脚本==计算==1-100奇数和
        • ① 思路
        • ② 落地实现(条条大路通罗马)
        • ③ 循环控制语句
      • ㈡ 判断所输整数是否为质数
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户
        • ① 思路
        • ② 落地实现
    • 3. 课堂练习
      • ㈠ 批量创建用户
      • ㈡ 局域网内脚本检查主机网络通讯
      • ㈢ 判断闰年
    • 2. 应用案例
      • ㈠ 脚本计算1-50偶数和
      • ㈡ 脚本同步系统时间
        • ① 具体需求
        • ② 思路
        • ③ 落地实现
    • 1. until语法结构
    • 2. 应用案例
      • ㈡ 思路
      • ㈢ 落地实现
  • 四、课后作业
  • 一、随机数
    • 1. 如何生成随机数?
    • 2. 实战案例
      • ㈠ 随机产生以139开头的电话号码
        • ① 思路
        • ② 落地实现
      • ㈡ 随机抽出5位幸运观众
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户(密码随机产生)
        • ① 思路
        • ② 落地实现
  • 二、嵌套循环
      • ㈠ 打印指定图案
      • ㈡ 落地实现1
      • ㈢ 落地实现2
  • 三、阶段性补充总结
    • 1、变量定义
    • 2. 流程控制语句
    • 3. 循环语句
    • 4. 影响shell程序的内置命令
      • ㈠ 具体需求
      • ㈢ 落地实现
        • ② 最终实现
  • 一、case语句
    • 1. 语法结构
    • 2. 应用案例
      • ㈠ 脚本传不同值做不同事
      • ㈡ 根据用户需求选择做事
  • 二、==函数==
    • 1. 什么是函数?
    • 2. 如何定义函数?
      • ㈠ 当前命令行调用
      • ㈡ 定义到用户的环境变量中
      • ㈢ 脚本中调用
    • 1. 任务背景
    • 2. 具体要求
    • 3. 综合分析
    • 4. 落地实现
  • 四、正则表达式
    • 2. 正则能干什么?
    • 3. 正则当中名词解释
      • ㈠ 正则中普通常用的元字符
      • ㈡ 正则中其他常用元字符
      • ㈢ 扩展类正则常用元字符
    • 6. 正则表达式总结
  • 五、正则元字符一栏表
  • 六、正则练习作业
    • 1. 文件准备
    • 2. 具体要求
    • 脚本搭建web服务

#本机课程目标

  • 掌握for循环语句的基本语法结构
  • 掌握while和until循环语句的基本语法结构

一、for循环语句

关键词:爱的魔力转圈圈😇

1. for循环语法结构

列表循环

列表for循环:用于将一组命令执行**已知的次数**

  • 基本语法格式
for variable in {list}docommand command…done
或者
for variable in a b cdocommandcommanddone
  • 举例说明
# for var in {1..10};do echo $var;done
# for var in 1 2 3 4 5;do echo $var;done
# for var in `seq 10`;do echo $var;done
# for var in $(seq 10);do echo $var;done
# for var in {0..10..2};do echo $var;done
# for var in {2..10..2};do echo $var;done
# for var in {10..1};do echo $var;done
# for var in {10..1..-2};do echo $var;done
# for var in `seq 10 -2 1`;do echo $var;done

㈡ 不带列表循环

不带列表的for循环执行时由用户指定参数和参数的个数

  • 基本语法格式
for variabledocommand command…done
  • 举例说明
#!/bin/bash
for var
do
echo $var
doneecho "脚本后面有$#个参数"

㈢ 类C风格的for循环

  • 基本语法结构
for(( expr1;expr2;expr3 ))docommandcommand…done
for (( i=1;i<=5;i++))doecho $idoneexpr1:定义变量并赋初值
expr2:决定是否进行循环(条件)
expr3:决定循环变量如何改变,决定循环什么时候退出
  • 举例说明
 # for ((i=1;i<=5;i++));do echo $i;done# for ((i=1;i<=10;i+=2));do echo $i;done# for ((i=2;i<=10;i+=2));do echo $i;done

2. 应用案例

㈠ 脚本计算1-100奇数和

① 思路

  1. 定义一个变量来保存奇数的和 sum=0
  2. 找出1-100的奇数,保存到另一个变量里 i=遍历出来的奇数
  3. 从1-100中找出奇数后,再相加,然后将和赋值给变量 循环变量 for
  4. 遍历完毕后,将sum的值打印出来

② 落地实现(条条大路通罗马)

#!/bin/env bash
# 计算1-100的奇数和
# 定义变量来保存奇数和
sum=0#for循环遍历1-100的奇数,并且相加,把结果重新赋值给sumfor i in {1..100..2}
dolet sum=$sum+$i
done
#打印所有奇数的和
echo "1-100的奇数和是:$sum"方法1:
#!/bin/bash
sum=0
for i in {1..100..2}
dosum=$[$i+$sum]
done
echo "1-100的奇数和为:$sum"方法2:
#!/bin/bash
sum=0
for ((i=1;i<=100;i+=2))
dolet sum=$i+$sum
done
echo "1-100的奇数和为:$sum"方法3:
#!/bin/bash
sum=0
for ((i=1;i<=100;i++))
doif [ $[$i%2] -ne 0 ];thenlet sum=$sum+$ifi
或者
test $[$i%2] -ne 0 && let sum=$sum+$idone
echo "1-100的奇数和为:$sum"方法4:
sum=0
for ((i=1;i<=100;i++))
doif [ $[$i%2] -eq 0 ];thencontinueelselet sum=$sum+$ifi
done
echo "1-100的奇数和为:$sum"#!/bin/bash
sum=0
for ((i=1;i<=100;i++))
dotest $[$i%2] -eq 0 && continue || let sum=sum+$i
done
echo "1-100的奇数和是:$sum"

③ 循环控制语句

循环体: do…done之间的内容

  • continue:继续;表示循环体内下面的代码不执行,重新开始下一次循环
  • break:打断;马上停止执行本次循环,执行循环体后面的代码
  • exit:表示直接跳出程序
[root@server ~]# cat for5.sh 
#!/bin/bash
for i in {1..5}
dotest $i -eq 2 && break || touch /tmp/file$i
done
echo hello hahahah

㈡ 判断所输整数是否为质数

质数(素数):只能被1和它本身整除的数叫质数。
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

① 思路

  1. 让用户输入一个数,保存到一个变量里 read -p "请输入一个正整数:" num
  2. 如果能被其他数整除就不是质数——>$num%$i 是否等于0 $i=2到​$num-1
  3. 如果输入的数是1或者2取模根据上面判断又不符合,所以先排除1和2
  4. 测试序列从2开始,输入的数是4——>得出结果$num不能和$i相等,并且$num不能小于$i

② 落地实现

#!/bin/env bash
#定义变量来保存用户所输入数字
read -p "请输入一个正整数字:" number#先排除用户输入的数字1和2
[ $number -eq 1 ] && echo "$number不是质数" && exit
[ $number -eq 2 ] && echo "$number是质数" && exit#循环判断用户所输入的数字是否质数for i in `seq 2 $[$number-1]`do[ $[$number%$i] -eq 0 ] && echo "$number不是质数" && exitdone
echo "$number是质数"优化思路:没有必要全部产生2~$[$number-1]序列,只需要产生一半即可。更好解决办法:类C风格完美避开了生成序列的坑
for (( i=2;i<=$[$number-1];i++))
do[ $[$number%$i] -eq 0 ] && echo "$number不是质数" && exitdone
echo "$number是质数"

㈢ 批量创建用户

**需求:**批量加5个新用户,以u1到u5命名,并统一加一个新组,组名为class,统一改密码为123

① 思路

  1. 添加用户的命令 useradd -G class
  2. 判断class组是否存在 grep -w ^class /etc/group 或者groupadd class
  3. 根据题意,判断该脚本循环5次来添加用户 for
  4. 给用户设置密码,应该放到循环体里面

② 落地实现

#!/bin/env bash
#判断class组是否存在
grep -w ^class /etc/group &>/dev/null
test $? -ne 0 && groupadd class#循环创建用户
for ((i=1;i<=5;i++))
douseradd -G class u$iecho 123|passwd --stdin u$i
done
#用户创建信息保存日志文件方法一:
#!/bin/bash
#判断class组是否存在
grep -w class /etc/group &>/dev/null
[ $? -ne 0 ] && groupadd class
#批量创建5个用户
for i in {1..5}
douseradd -G class u$iecho 123|passwd --stdin u$i
done方法二:
#!/bin/bash
#判断class组是否存在
cut -d: -f1 /etc/group|grep -w class &>/dev/null
[ $? -ne 0 ] && groupadd class#循环增加用户,循环次数5次,for循环,给用户设定密码
for ((i=1;i<=5;i++))
douseradd u$i -G classecho 123|passwd --stdin u$i
done方法三:
#!/bin/bash
grep -w class /etc/group &>/dev/null
test $? -ne 0 && groupadd class
或者
groupadd class &>/dev/nullfor ((i=1;i<=5;i++))
do
useradd -G class u$i && echo 123|passwd --stdin u$i
done

3. 课堂练习

㈠ 批量创建用户

**需求1:**批量新建5个用户stu1~stu5,要求这几个用户的家目录都在/rhome.

#!/bin/bash
#判断/rhome是否存在
[ -f /rhome ] && mv /rhome /rhome.bak
test ! -d /rhome && mkdir /rhome
或者
[ -f /rhome ] && mv /rhome /rhome.bak || [ ! -d /rhome ] && mkdir /rhome #创建用户,循环5次
for ((i=1;i<=5;i++))
douseradd -d /rhome/stu$i stu$iecho 123|passwd --stdin stu$i
done

㈡ 局域网内脚本检查主机网络通讯

需求2:

写一个脚本,局域网内,把能ping通的IP和不能ping通的IP分类,并保存到两个文本文件里

以10.1.1.1~10.1.1.10为例

10.1.1.1~10.1.1.254#!/bin/bash
#定义变量
ip=10.1.1
#循环去ping主机的IP
for ((i=1;i<=10;i++))
doping -c1 $ip.$i &>/dev/nullif [ $? -eq 0 ];thenecho "$ip.$i is ok" >> /tmp/ip_up.txtelseecho "$ip.$i is down" >> /tmp/ip_down.txtfi或者[ $? -eq 0 ] && echo "$ip.$i is ok" >> /tmp/ip_up.txt || echo "$ip.$i is down" >> /tmp/ip_down.txt
done[root@server shell03]# time ./ping.sh         real    0m24.129s
user    0m0.006s
sys     0m0.005s

延伸扩展:shell脚本并发

并行执行:
{程序}&表示将程序放到后台并行执行,如果需要等待程序执行完毕再进行下面内容,需要加wait#!/bin/bash
#定义变量
ip=10.1.1
#循环去ping主机的IP
for ((i=1;i<=10;i++))
do
{ping -c1 $ip.$i &>/dev/nullif [ $? -eq 0 ];thenecho "$ip.$i is ok" >> /tmp/ip_up.txtelseecho "$ip.$i is down" >> /tmp/ip_down.txtfi
}&
done
wait
echo "ip is ok...."[root@server ~]# time ./ping.sh 
ip is ok...real    0m3.091s
user    0m0.001s
sys     0m0.008s

㈢ 判断闰年

需求3:

输入一个年份,判断是否是润年(能被4整除但不能被100整除,或能被400整除的年份即为闰年)

#!/bin/bash
read -p "Please input year:(2017)" year
if [ $[$year%4] -eq 0 -a $[$year%100] -ne 0 ];thenecho "$year is leap year"
elif [ $[$year%400] -eq 0 ];thenecho "$year is leap year"
elseecho "$year is not leap year"
fi

##4. 总结

  • FOR循环语法结构
  • FOR循环可以结合条件判断和流程控制语句
    • do …done 循环体
    • 循环体里可以是命令集合,再加上条件判断以及流程控制
  • 控制循环语句
    • continue 继续,跳过本次循环,继续下一次循环
    • break 打断,跳出循环,执行循环体外的代码
    • exit 退出,直接退出程序

#二、while循环语句

特点:条件为真就进入循环;条件为假就退出循环

##1. while循环语法结构

while 表达式docommand...donewhile  [ 1 -eq 1 ] 或者 (( 1 > 2 ))docommandcommand...done

循环打印1-5数字

FOR循环打印:
for ((i=1;i<=5;i++))
doecho $i
donewhile循环打印:
i=1
while [ $i -le 5 ]
doecho $ilet i++
done

2. 应用案例

㈠ 脚本计算1-50偶数和

#!/bin/env bash
sum=0
for ((i=0;i<=50;i+=2))
dolet sum=$sum+$i  (let sum=sum+i)
done
echo "1-50的偶数和为:$sum"#!/bin/bash
#定义变量
sum=0
i=2
#循环打印1-50的偶数和并且计算后重新赋值给sum
while [ $i -le 50 ]
dolet sum=$sum+$ilet i+=2  或者 $[$i+2]
done
#打印sum的值
echo "1-50的偶数和为:$sum"

㈡ 脚本同步系统时间

① 具体需求

  1. 写一个脚本,30秒同步一次系统时间,时间同步服务器10.1.1.1
  2. 如果同步失败,则进行邮件报警,每次失败都报警
  3. 如果同步成功,也进行邮件通知,但是成功100次才通知一次

② 思路

  1. 每隔30s同步一次时间,该脚本是一个死循环 while 循环

  2. 同步失败发送邮件 1) ntpdate 10.1.1.1 2) rdate -s 10.1.1.1

  3. 同步成功100次发送邮件 定义变量保存成功次数

③ 落地实现

#!/bin/env bash
# 该脚本用于时间同步
NTP=10.1.1.1
count=0
while true
dontpdate $NTP &>/dev/nullif [ $? -ne 0 ];thenecho "system date failed" |mail -s "check system date"  root@localhostelselet count++if [ $count -eq 100 ];thenecho "systemc date success" |mail -s "check system date"  root@localhost && count=0fifi
sleep 30
done#!/bin/bash
#定义变量
count=0
ntp_server=10.1.1.1
while true
dordate -s $ntp-server &>/dev/nullif [ $? -ne 0 ];thenecho "system date failed" |mail -s 'check system date'  root@localhost	elselet count++if [ $[$count%100] -eq 0 ];thenecho "system date successfull" |mail -s 'check system date'  root@localhost && count=0fifi
sleep 3
done以上脚本还有更多的写法,课后自己完成

#三、until循环

特点条件为假就进入循环;条件为真就退出循环

1. until语法结构

until expression   [ 1 -eq 1 ]  (( 1 >= 1 ))docommandcommand...done

打印1-5数字

i=1
while [ $i -le 5 ]
doecho $ilet i++
donei=1
until [ $i -gt 5 ]
doecho $ilet i++
done

2. 应用案例

###㈠ 具体需求

  1. 使用until语句批量创建10个用户,要求stu1—stu5用户的UID分别为1001—1005;
  2. stu6~stu10用户的家目录分别在/rhome/stu6—/rhome/stu10

㈡ 思路

  1. 创建用户语句 useradd -u|useradd -d
  2. 使用循环语句(until)批量创建用户 until循环语句结构
  3. 判断用户前5个和后5个 条件判断语句

㈢ 落地实现

#!/bin/env bash
if [ -d /rhome ];thenecho "/rhome目录已存在"
elsemkdir /rhomeecho "/rhome不存在,已完成创建"
fii=1
until [ $i -gt 10 ]
doif [ $i -le 5 ];thenuseradd -u $[1000+$i] stu$iecho 123|passwd --stdin stu$ielseuseradd -d /rhome/stu$i stu$iecho 123|passwd --stdin stu$ifi
let i++
done==================================================#!/bin/bash
i=1
until [ $i -gt 10 ]
doif [ $i -le 5 ];thenuseradd -u $[1000+$i] stu$i && echo 123|passwd --stdin stu$ielse[ ! -d /rhome ] && mkdir /rhomeuseradd -d /rhome/stu$i stu$i && echo 123|passwd --stdin stu$i		fi
let i++
done

四、课后作业

  1. 判断/tmp/run目录是否存在,如果不存在就建立,如果存在就删除目录里所有文件
  2. 输入一个路径,判断路径是否存在,而且输出是文件还是目录,如果是链接文件,还得输出是 有效的连接还是无效的连接
  3. 交互模式要求输入一个ip,然后脚本判断这个IP 对应的主机是否 能ping 通,输出结果类似于:
    Server 10.1.1.20 is Down! 最后要求把结果邮件到本地管理员root@localhost mail01@localhost
  4. 写一个脚本/home/program,要求当给脚本输入参数hello时,脚本返回world,给脚本输入参数world时,脚本返回hello。而脚本没有参数或者参数错误时,屏幕上输出“usage:/home/program hello or world”
  5. 写一个脚本自动搭建nfs服务

文章目录

    • typora-copy-images-to: pictures typora-root-url: ..\..\pictures
  • 一、for循环语句
    • 1. for循环语法结构
      • ㈠ ==列表==循环
      • ㈡ 不带列表循环
      • ㈢ 类C风格的for循环
    • 2. 应用案例
      • ㈠ 脚本==计算==1-100奇数和
        • ① 思路
        • ② 落地实现(条条大路通罗马)
        • ③ 循环控制语句
      • ㈡ 判断所输整数是否为质数
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户
        • ① 思路
        • ② 落地实现
    • 3. 课堂练习
      • ㈠ 批量创建用户
      • ㈡ 局域网内脚本检查主机网络通讯
      • ㈢ 判断闰年
    • 2. 应用案例
      • ㈠ 脚本计算1-50偶数和
      • ㈡ 脚本同步系统时间
        • ① 具体需求
        • ② 思路
        • ③ 落地实现
    • 1. until语法结构
    • 2. 应用案例
      • ㈡ 思路
      • ㈢ 落地实现
  • 四、课后作业
    • typora-copy-images-to: pictures typora-root-url: ..\..\pictures
  • 一、==for循环语句==
    • 1. for循环语法结构
      • ㈠ ==列表==循环
      • ㈡ 不带列表循环
      • ㈢ 类C风格的for循环
    • 2. 应用案例
      • ㈠ 脚本==计算==1-100奇数和
        • ① 思路
        • ② 落地实现(条条大路通罗马)
        • ③ 循环控制语句
      • ㈡ 判断所输整数是否为质数
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户
        • ① 思路
        • ② 落地实现
    • 3. 课堂练习
      • ㈠ 批量创建用户
      • ㈡ 局域网内脚本检查主机网络通讯
      • ㈢ 判断闰年
    • 2. 应用案例
      • ㈠ 脚本计算1-50偶数和
      • ㈡ 脚本同步系统时间
        • ① 具体需求
        • ② 思路
        • ③ 落地实现
    • 1. until语法结构
    • 2. 应用案例
      • ㈡ 思路
      • ㈢ 落地实现
  • 四、课后作业
  • 一、随机数
    • 1. 如何生成随机数?
    • 2. 实战案例
      • ㈠ 随机产生以139开头的电话号码
        • ① 思路
        • ② 落地实现
      • ㈡ 随机抽出5位幸运观众
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户(密码随机产生)
        • ① 思路
        • ② 落地实现
  • 二、嵌套循环
      • ㈠ 打印指定图案
      • ㈡ 落地实现1
      • ㈢ 落地实现2
  • 三、阶段性补充总结
    • 1、变量定义
    • 2. 流程控制语句
    • 3. 循环语句
    • 4. 影响shell程序的内置命令
      • ㈠ 具体需求
      • ㈢ 落地实现
        • ② 最终实现
  • 一、case语句
    • 1. 语法结构
    • 2. 应用案例
      • ㈠ 脚本传不同值做不同事
      • ㈡ 根据用户需求选择做事
  • 二、==函数==
    • 1. 什么是函数?
    • 2. 如何定义函数?
      • ㈠ 当前命令行调用
      • ㈡ 定义到用户的环境变量中
      • ㈢ 脚本中调用
    • 1. 任务背景
    • 2. 具体要求
    • 3. 综合分析
    • 4. 落地实现
  • 四、正则表达式
    • 2. 正则能干什么?
    • 3. 正则当中名词解释
      • ㈠ 正则中普通常用的元字符
      • ㈡ 正则中其他常用元字符
      • ㈢ 扩展类正则常用元字符
    • 6. 正则表达式总结
  • 五、正则元字符一栏表
  • 六、正则练习作业
    • 1. 文件准备
    • 2. 具体要求
    • 脚本搭建web服务

#课程目标

  • 掌握for循环语句的基本语法结构
  • 掌握while和until循环语句的基本语法结构
  • 能会使用RANDOM产生随机数
  • 理解嵌套循环

一、随机数

关键词:一切都是未知数,永远不知道明天会抽什么风🎐😅

1. 如何生成随机数?

系统变量RANDOM,默认会产生0~32767的随机整数

**前言:**要想调用变量,不管你是什么变量都要给钱,而且是美元💲

打印一个随机数
echo $RANDOM
查看系统上一次生成的随机数
# set|grep RANDOM
RANDOM=28325产生0~1之间的随机数
echo $[$RANDOM%2]产生0~2之间的随机数
echo $[$RANDOM%3]产生0~3之间的随机数
echo $[$RANDOM%4]产生0~9内的随机数
echo $[$RANDOM%10]产生0~100内的随机数
echo $[$RANDOM%101]产生50-100之内的随机数
echo $[$RANDOM%51+50]产生三位数的随机数
echo $[$RANDOM%900+100]

2. 实战案例

㈠ 随机产生以139开头的电话号码

具体需求1:

写一个脚本,产生一个phonenum.txt文件,随机产生以139开头的手机号1000个,每个一行。

① 思路

  1. 产生1000个电话号码,脚本需要循环1000次 FOR WHILE UNTIL
  2. 139+8位,后8位随机产生,可以让每一位数字都随机产生 echo $[$RANDOM%10]
  3. 将随机产生的数字分别保存到变量里,然后加上139保存到文件里

② 落地实现


#!/bin/env bash
#产生1000个以139开头的电话号码并保存文件phonenum.txt
file=/shell03/phonenum.txt
for ((i=1;i<=1000;i++))
don1=$[$RANDOM%10]n2=$[$RANDOM%10]n3=$[$RANDOM%10]n4=$[$RANDOM%10]n5=$[$RANDOM%10]n6=$[$RANDOM%10]n7=$[$RANDOM%10]n8=$[$RANDOM%10]echo "139$n1$n2$n3$n4$n5$n6$n7$n8" >> $file
done#!/bin/bash
# random phonenum
# 循环1000次产生电话号码并保存到文件
for i in {1..1000}
don1=$[RANDOM%10]n2=$[RANDOM%10]n3=$[RANDOM%10]n4=$[RANDOM%10]n5=$[RANDOM%10]n6=$[RANDOM%10]n7=$[RANDOM%10]n8=$[RANDOM%10]echo "139$n1$n2$n3$n4$n5$n6$n7$n8" >> phonenum.txt
done#!/bin/bash
i=1
while [ $i -le 1000 ]
don1=$[$RANDOM%10]n2=$[$RANDOM%10]n3=$[$RANDOM%10]n4=$[$RANDOM%10]n5=$[$RANDOM%10]n6=$[$RANDOM%10]n7=$[$RANDOM%10]n8=$[$RANDOM%10]echo "139$n1$n2$n3$n4$n5$n6$n7$n8" >> phonenum.txtlet i++
donecontinue:继续,跳过本次循环,执行下一次循环
break:打断,执行循环体外的代码do..done外
exit:退出程序#!/bin/bash
for i in {1..1000}
don1=$[$RANDOM%10]n2=$[$RANDOM%10]n3=$[$RANDOM%10]n4=$[$RANDOM%10]n5=$[$RANDOM%10]n6=$[$RANDOM%10]n7=$[$RANDOM%10]n8=$[$RANDOM%10]echo "139$n1$n2$n3$n4$n5$n6$n7$n8" >> phonenum.txt
done#!/bin/bash
#create phone num file
for ((i=1;i<=1000;i++))
don1=$[$RANDOM%10]n2=$[$RANDOM%10]n3=$[$RANDOM%10]n4=$[$RANDOM%10]n5=$[$RANDOM%10]n6=$[$RANDOM%10]n7=$[$RANDOM%10]n8=$[$RANDOM%10]echo "139$n1$n2$n3$n4$n5$n6$n7$n8" |tee -a phonenum.txt
done#!/bin/bash
count=0
while true
don1=$[$RANDOM%10]n2=$[$RANDOM%10]n3=$[$RANDOM%10]n4=$[$RANDOM%10]n5=$[$RANDOM%10]n6=$[$RANDOM%10]n7=$[$RANDOM%10]n8=$[$RANDOM%10]echo "139$n1$n2$n3$n4$n5$n6$n7$n8" |tee -a phonenum.txt && let count++if [ $count -eq 1000 ];thenbreakfi
done

㈡ 随机抽出5位幸运观众

具体需求:

  1. 在上面的1000个手机号里抽奖5个幸运观众,显示出这5个幸运观众。
  2. 但只显示头3个数和尾号的4个数,中间的都用*代替

① 思路

  1. 确定幸运观众所在的行 0-1000 随机找出一个数字 $[$RANDOM%1000+1]
  2. 将电话号码提取出来 head -随机产生行号 phonenum.txt |tail -1
  3. 显示前3个和后4个数到屏幕 echo 139****

② 落地实现

#!/bin/bash
#定义变量
phone=/shell03/phonenum.txt
#循环抽出5位幸运观众
for ((i=1;i<=5;i++))
do#定位幸运观众所在行号line=`wc -l $phone |cut -d' ' -f1`luck_line=$[RANDOM%$line+1]#取出幸运观众所在行的电话号码luck_num=`head -$luck_line $phone|tail -1`#显示到屏幕echo "139****${luck_num:7:4}"echo $luck_num >> luck.txt#删除已经被抽取的幸运观众号码#sed -i "/$luck_num/d" $phone
done#!/bin/bash
file=/shell04/phonenum.txt
for i in {1..5}
dofile_num=`wc -l $file |cut -d' ' -f1`line=`echo $[$RANDOM%$file_num+1]`luck=`head -n $line  $file|tail -1`echo "139****${luck:7:4}" && echo $luck >> /shell04/luck_num.txt
done#!/bin/bash
for ((i=1;i<=5;i++))
do
file=phonenum.txt
line=`cat phonenum.txt |wc -l`	1000
luckline=$[$RANDOM%$line+1]
phone=`cat $file|head -$luckline|tail -1`
echo "幸运观众为:139****${phone:7:4}"
done或者
#!/bin/bash
# choujiang
phone=phonenum.txt
for ((i=1;i<=5;i++))
donum=`wc -l phonenum.txt |cut -d' ' -f1`line=`echo $[$RANDOM%$num+1]`luck=`head -$line $phone |tail -1`sed -i "/$luck/d" $phoneecho "幸运观众是:139****${luck:7:4}"
done

㈢ 批量创建用户(密码随机产生)

**需求:**批量创建5个用户,每个用户的密码为一个随机数

① 思路

  1. 循环5次创建用户
  2. 产生一个密码文件来保存用户的随机密码
  3. 从密码文件中取出随机密码赋值给用户

② 落地实现

#!/bin/bash
#crate user and set passwd
#产生一个保存用户名和密码的文件
echo user0{1..5}:itcast$[$RANDOM%9000+1000]#@~|tr ' ' '\n'>> user_pass.file#循环创建5个用户
for ((i=1;i<=5;i++))
douser=`head -$i user_pass.file|tail -1|cut -d: -f1`pass=`head -$i user_pass.file|tail -1|cut -d: -f2`useradd $userecho $pass|passwd --stdin $user
done或者
for i in `cat user_pass.file`
douser=`echo $i|cut -d: -f1`pass=`echo $i|cut -d: -f2`useradd $userecho $pass|passwd --stdin $user
done#!/bin/bash
#crate user and set passwd
#产生一个保存用户名和密码的文件
echo user0{1..3}:itcast$[$RANDOM%9000+1000]#@~|tr ' ' '\n'|tr ':' ' ' >> user_pass.file
#循环创建5个用户
while read user pass
do
useradd $user
echo $pass|passwd --stdin $user
done < user_pass.filepwgen工具产生随机密码:
[root@server shell04]# pwgen -cn1 12
Meep5ob1aesa
[root@server shell04]# echo user0{1..3}:$(pwgen -cn1 12)
user01:Bahqu9haipho user02:Feiphoh7moo4 user03:eilahj5eth2R
[root@server shell04]# echo user0{1..3}:$(pwgen -cn1 12)|tr ' ' '\n'
user01:eiwaShuZo5hi
user02:eiDeih7aim9k
user03:aeBahwien8co

二、嵌套循环

关键字:大圈套小圈

🕒时钟:分针与秒针,秒针转⼀圈(60格),分针转1格。循环嵌套就是外层循环⼀次,内层循环⼀轮。

  1. 一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。
  2. 每次外部循环都会触发内部循环,直至内部循环完成,才接着执行下一次的外部循环。
  3. for循环、while循环和until循环可以相互嵌套。

##1. 应用案例

㈠ 打印指定图案

1
12
123
1234
123455
54
543
5432
54321

㈡ 落地实现1

X轴:
for ((i=1;i<=5;i++));do echo -n $i;done
Y轴:
负责打印换行#!/bin/bash
for ((y=1;y<=5;y++))
dofor ((x=1;x<=$y;x++))doecho -n $xdone
echo
done#!/bin/bash
for ((y=1;y<=5;y++))
dox=1while [ $x -le $y ]doecho -n $xlet x++done
echo
done

㈢ 落地实现2

Y轴:打印换行
X轴:打印数字 5-1#!/bin/bash
y=5
while (( $y >= 1 ))
dofor ((x=5;x>=$y;x--))doecho -n $xdone
echo
let y--
done#!/bin/bash
for (( y=5;y>=1;y--))
dofor (( x=5;x>=$y;x--))doecho -n $xdone
echo
done#!/bin/bash
y=5
while [ $y -ge 1 ]
dofor ((x=5;x>=$y;x--))doecho -n $xdone
echo
let y--
done#!/bin/bash
y=1
until (( $y >5 ))
dox=1while (( $x <= $y ))doecho -n $[6-$x]let x++done	
echo
let y++
done课后打印:
54321
5432
543
54
5

##2. 课堂练习

打印九九乘法表(三种方法)

1*1=11*2=2   2*2=41*3=3   2*3=6   3*3=91*4=4   2*4=8   3*4=12  4*4=161*5=5   2*5=10  3*5=15  4*5=20  5*5=251*6=6   2*6=12  3*6=18  4*6=24  5*6=30  6*6=361*7=7   2*7=14  3*7=21  4*7=28  5*7=35  6*7=42  7*7=491*8=8   2*8=16  3*8=24  4*8=32  5*8=40  6*8=48  7*8=56  8*8=641*9=9   2*9=18  3*9=27  4*9=36  5*9=45  6*9=54  7*9=63  8*9=72  9*9=81Y轴:循环9次,打印9行空行
X轴:循环次数和Y轴相关;打印的是X和Y轴乘积 $[] $(())#!/bin/bash
for ((y=1;y<=9;y++))
dofor ((x=1;x<=$y;x++))doecho -ne "$x*$y=$[$x*$y]\t"done
echo
echo
done#!/bin/bash
y=1
while [ $y -le 9 ]
dox=1while [ $x -le $y ]doecho -ne "$x*$y=$[$x*$y]\t"let x++done
echo
echo
let y++
done或者
#!/bin/bash
for i in `seq 9`
dofor j in `seq $i`doecho -ne  "$j*$i=$[$i*$j]\t"done
echo
echo
done
或者
#!/bin/bash
y=1
until [ $y -gt 9 ]
dox=1until [ $x -gt $y ]doecho -ne "$x*$y=$[ $x*$y ]\t"let x++done
echo
echo
let y++
done

三、阶段性补充总结

1、变量定义


2. 流程控制语句


3. 循环语句


4. 影响shell程序的内置命令

exit			退出整个程序
break		   结束当前循环,或跳出本层循环
continue 	忽略本次循环剩余的代码,直接进行下一次循环
shift			使位置参数向左移动,默认移动1位,可以使用shift 2:
true
false

举例说明:

以下脚本都能够实现用户自定义输入数字,然后脚本计算和:
[root@MissHou shell04]# cat shift.sh 
#!/bin/bash
sum=0
while [ $# -ne 0 ]
do
let sum=$sum+$1
shift
done
echo sum=$sum[root@MissHou shell04]# cat for3.sh 
#!/bin/bash
sum=0
for i
do
let sum=$sum+$i
done
echo sum=$sum

##4. 补充扩展expect

expect 自动应答 tcl语言

**需求1:**A远程登录到server上什么都不做

#!/usr/bin/expect
# 开启一个程序
spawn ssh root@10.1.1.1
# 捕获相关内容
expect {"(yes/no)?" { send "yes\r";exp_continue }"password:" { send "123456\r" }
}
interact   //交互脚本执行方式:
# ./expect1.sh
# /shell04/expect1.sh
# expect -f expect1.sh1)定义变量
#!/usr/bin/expect
set ip 10.1.1.2
set pass 123456
set timeout 5
spawn ssh root@$ip
expect {"yes/no" { send "yes\r";exp_continue }"password:" { send "$pass\r" }
}
interact2)使用位置参数
#!/usr/bin/expect
set ip [ lindex $argv 0 ]
set pass [ lindex $argv 1 ]
set timeout 5
spawn ssh root@$ip
expect {"yes/no" { send "yes\r";exp_continue }"password:" { send "$pass\r" }
}
interact

**需求2:**A远程登录到server上操作

#!/usr/bin/expect
set ip 10.1.1.1
set pass 123456
set timeout 5
spawn ssh root@$ip
expect {"yes/no" { send "yes\r";exp_continue }"password:" { send "$pass\r" }
}expect "#"
send "rm -rf /tmp/*\r"
send "touch /tmp/file{1..3}\r"
send "date\r"
send "exit\r"
expect eof

**需求3:**shell脚本和expect结合使用,在多台服务器上创建1个用户

[root@server shell04]# cat ip.txt 
10.1.1.1 123456
10.1.1.2 1234561. 循环
2. 登录远程主机——>ssh——>从ip.txt文件里获取IP和密码分别赋值给两个变量
3. 使用expect程序来解决交互问题#!/bin/bash
# 循环在指定的服务器上创建用户和文件
while read ip pass
do/usr/bin/expect <<-END &>/dev/nullspawn ssh root@$ipexpect {"yes/no" { send "yes\r";exp_continue }"password:" { send "$pass\r" }}expect "#" { send "useradd yy1;rm -rf /tmp/*;exit\r" }expect eofEND
done < ip.txt#!/bin/bash
cat ip.txt|while read ip pass
do{/usr/bin/expect <<-HOUspawn ssh root@$ipexpect {"yes/no" { send "yes\r";exp_continue }"password:" { send "$pass\r" }}expect "#"send "hostname\r"send "exit\r"expect eofHOU}&
done
wait
echo "user is ok...."或者
#!/bin/bash
while read ip pass
do{/usr/bin/expect <<-HOUspawn ssh root@$ipexpect {"yes/no" { send "yes\r";exp_continue }"password:" { send "$pass\r" }}expect "#"send "hostname\r"send "exit\r"expect eofHOU}&
done<ip.txt
wait
echo "user is ok...."

#四、综合案例

##1. 实战案例1

㈠ 具体需求

写一个脚本,将跳板机上yunwei用户的公钥推送到局域网内可以ping通的所有机器上

说明:主机和密码文件已经提供

10.1.1.1:123456

10.1.1.2:123456

###㈡ 案例分析

  • 关闭防火墙和selinux
  • 判断ssh服务是否开启(默认ok)
  • 循环判断给定密码文件里的哪些IP是可以ping通
  • 判断IP是否可以ping通——>$?—>流程控制语句
  • 密码文件里获取主机的IP和密码保存变量
  • 判断公钥是否存在—>不存在创建它
  • ssh-copy-id 将跳板机上的yunwei用户的公钥推送到远程主机—>expect解决交互
  • 将ping通的主机IP单独保存到一个文件
  • 测试验证

㈢ 落地实现

####① 代码拆分

1.判断yunwei用户的公钥是否存在
[ ! -f /hoem/yunwei/.ssh/id_rsa ] && ssh-keygen -P '' -f ./id_rsa2.获取IP并且判断是否可以ping通
1)主机密码文件ip.txt10.1.1.1:12345610.1.1.2:123456
2) 循环判断主机是否ping通tr ':' ' ' < ip.txt|while read ip passdoping -c1 $ip &>/dev/nullif [ $? -eq 0 ];then推送公钥fidone3.非交互式推送公钥
/usr/bin/expect <<-END &>/dev/nullspawn ssh-copy-id root@$ipexpect {"yes/no" { send "yes\r";exp_continue }"password:" { send "$pass\r" }}expect eofEND

② 最终实现

  1. 环境准备
jumper-server	有yunwei用户yunwei用户sudo授权:
visudo
## Allow root to run any commands anywhere
root    ALL=(ALL)       ALL
yunwei  ALL=(root)      NOPASSWD:ALL,!/sbin/shutdown,!/sbin/init,!/bin/rm -rf /解释说明:
1)第一个字段yunwei指定的是用户:可以是用户名,也可以是别名。每个用户设置一行,多个用户设置多行,也可以将多个用户设置成一个别名后再进行设置。
2)第二个字段ALL指定的是用户所在的主机:可以是ip,也可以是主机名,表示该sudo设置只在该主机上生效,ALL表示在所有主机上都生效!限制的一般都是本机,也就是限制使用这个文件的主机;一般都指定为"ALL"表示所有的主机,不管文件拷到那里都可以用。比如:10.1.1.1=...则表示只在当前主机生效。
3)第三个字段(root)括号里指定的也是用户:指定以什么用户身份执行sudo,即使用sudo后可以享有所有root账号下的权限。如果要排除个别用户,可以在括号内设置,比如ALL=(ALL,!oracle,!pos)。
4)第四个字段ALL指定的是执行的命令:即使用sudo后可以执行所有的命令。除了关机和删除根内容以外;也可以设置别名。NOPASSWD: ALL表示使用sudo的不需要输入密码。
5)也可以授权给一个用户组%admin ALL=(ALL) ALL	表示admin组里的所有成员可以在任何主机上以任何用户身份执行任何命令
  1. 脚本实现
#!/bin/bash
#判断公钥是否存在
[ ! -f /home/yunwei/.ssh/id_rsa ] && ssh-keygen -P '' -f ~/.ssh/id_rsa#循环判断主机是否ping通,如果ping通推送公钥
tr ':' ' ' < /shell04/ip.txt|while read ip pass
do
{ping -c1 $ip &>/dev/nullif [ $? -eq 0 ];thenecho $ip >> ~/ip_up.txt/usr/bin/expect <<-END &>/dev/nullspawn ssh-copy-id root@$ipexpect {"yes/no" { send "yes\r";exp_continue }"password:" { send "$pass\r" }}expect eofENDfi
}&
done
wait
echo "公钥已经推送完毕,正在测试...."
#测试验证
remote_ip=`tail -1 ~/ip_up.txt`
ssh root@$remote_ip hostname &>/dev/null
test $? -eq 0 && echo "公钥成功推送完毕"

##2. 实战案例2

写一个脚本,统计web服务的不同连接状态个数

#!/bin/bash
#count_http_80_state
#统计每个状态的个数
declare -A array1
states=`ss -ant|grep 80|cut -d' ' -f1`
for i in $states
dolet array1[$i]++
done
#通过遍历数组里的索引和元素打印出来
for j in ${!array1[@]}
doecho $j:${array1[$j]}
done

#五、课后实战

1、将/etc/passwd里的用户名分类,分为管理员用户,系统用户,普通用户。
2、写一个倒计时脚本,要求显示离2019年1月1日(元旦)的凌晨0点,还有多少天,多少时,多少分,多少秒。
3、写一个脚本把一个目录内的所有空文件都删除,最后输出删除的文件的个数。

文章目录

    • typora-copy-images-to: pictures typora-root-url: ..\..\pictures
  • 一、for循环语句
    • 1. for循环语法结构
      • ㈠ ==列表==循环
      • ㈡ 不带列表循环
      • ㈢ 类C风格的for循环
    • 2. 应用案例
      • ㈠ 脚本==计算==1-100奇数和
        • ① 思路
        • ② 落地实现(条条大路通罗马)
        • ③ 循环控制语句
      • ㈡ 判断所输整数是否为质数
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户
        • ① 思路
        • ② 落地实现
    • 3. 课堂练习
      • ㈠ 批量创建用户
      • ㈡ 局域网内脚本检查主机网络通讯
      • ㈢ 判断闰年
    • 2. 应用案例
      • ㈠ 脚本计算1-50偶数和
      • ㈡ 脚本同步系统时间
        • ① 具体需求
        • ② 思路
        • ③ 落地实现
    • 1. until语法结构
    • 2. 应用案例
      • ㈡ 思路
      • ㈢ 落地实现
  • 四、课后作业
    • typora-copy-images-to: pictures typora-root-url: ..\..\pictures
  • 一、==for循环语句==
    • 1. for循环语法结构
      • ㈠ ==列表==循环
      • ㈡ 不带列表循环
      • ㈢ 类C风格的for循环
    • 2. 应用案例
      • ㈠ 脚本==计算==1-100奇数和
        • ① 思路
        • ② 落地实现(条条大路通罗马)
        • ③ 循环控制语句
      • ㈡ 判断所输整数是否为质数
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户
        • ① 思路
        • ② 落地实现
    • 3. 课堂练习
      • ㈠ 批量创建用户
      • ㈡ 局域网内脚本检查主机网络通讯
      • ㈢ 判断闰年
    • 2. 应用案例
      • ㈠ 脚本计算1-50偶数和
      • ㈡ 脚本同步系统时间
        • ① 具体需求
        • ② 思路
        • ③ 落地实现
    • 1. until语法结构
    • 2. 应用案例
      • ㈡ 思路
      • ㈢ 落地实现
  • 四、课后作业
  • 一、随机数
    • 1. 如何生成随机数?
    • 2. 实战案例
      • ㈠ 随机产生以139开头的电话号码
        • ① 思路
        • ② 落地实现
      • ㈡ 随机抽出5位幸运观众
        • ① 思路
        • ② 落地实现
      • ㈢ 批量创建用户(密码随机产生)
        • ① 思路
        • ② 落地实现
  • 二、嵌套循环
      • ㈠ 打印指定图案
      • ㈡ 落地实现1
      • ㈢ 落地实现2
  • 三、阶段性补充总结
    • 1、变量定义
    • 2. 流程控制语句
    • 3. 循环语句
    • 4. 影响shell程序的内置命令
      • ㈠ 具体需求
      • ㈢ 落地实现
        • ② 最终实现
  • 一、case语句
    • 1. 语法结构
    • 2. 应用案例
      • ㈠ 脚本传不同值做不同事
      • ㈡ 根据用户需求选择做事
  • 二、==函数==
    • 1. 什么是函数?
    • 2. 如何定义函数?
      • ㈠ 当前命令行调用
      • ㈡ 定义到用户的环境变量中
      • ㈢ 脚本中调用
    • 1. 任务背景
    • 2. 具体要求
    • 3. 综合分析
    • 4. 落地实现
  • 四、正则表达式
    • 2. 正则能干什么?
    • 3. 正则当中名词解释
      • ㈠ 正则中普通常用的元字符
      • ㈡ 正则中其他常用元字符
      • ㈢ 扩展类正则常用元字符
    • 6. 正则表达式总结
  • 五、正则元字符一栏表
  • 六、正则练习作业
    • 1. 文件准备
    • 2. 具体要求
    • 脚本搭建web服务

#课程目标

  • 掌握case语句的基本语法结构
  • 掌握函数的定义及调用
  • 掌握常用的正则表达式元字符含义

一、case语句

关键词:确认过眼神,你是对的人💑

  1. case语句为多重匹配语句
  2. 如果匹配成功,执行相匹配的命令

1. 语法结构

说明:pattern表示需要匹配的模式case var in             定义变量;var代表是变量名
pattern 1)              模式1;| 分割多个模式,相当于orcommand1            需要执行的语句;;                  两个分号代表命令结束
pattern 2)command2;;
pattern 3)command3;;*)              default,不满足以上模式,默认执行*)下面的语句command4;;
esac							esac表示case语句结束

2. 应用案例

㈠ 脚本传不同值做不同事

**具体需求:**当给程序传入start、stop、restart三个不同参数时分别执行相应命令

#!/bin/env bash
case $1 instart|S)service apache start &>/dev/null && echo "apache 启动成功";;stop|T)service apache stop &>/dev/null && echo "apache 停止成功";;restart|R)service apache restart &>/dev/null && echo "apache 重启完毕";;*)echo "请输入要做的事情...";;
esac

㈡ 根据用户需求选择做事

具体需求:

脚本提示让用户输入需要管理的服务名,然后提示用户需要对服务做什么操作,如启动,关闭等操作

#!/bin/env bash
read -p "请输入你要管理的服务名称(vsftpd):" service
case $service invsftpd|ftp)read -p "请选择你需要做的事情(restart|stop):" actioncase $action instop|S)service vsftpd stop &>/dev/null && echo "该$serivce服务已经停止成功";;start)service vsftpd start &>/dev/null && echo "该$serivce服务已经成功启动";;esac;;httpd|apache)echo "apache hello world";;*)echo "请输入你要管理的服务名称(vsftpd)";;
esac

###㈢ 菜单提示让用户选择需要做的事

具体需求:

模拟一个多任务维护界面;当执行程序时先显示总菜单,然后进行选择后做相应维护监控操作

**********请选择*********
h	显示命令帮助
f	显示磁盘分区
d	显示磁盘挂载
m	查看内存使用
u	查看系统负载
q	退出程序
*************************

思路:

  1. 菜单打印出来
  2. 交互式让用户输入操作编号,然后做出相应处理

落地实现:

  1. 菜单打印(分解动作)
#!/bin/env bash
cat <<-EOFh	显示命令帮助f	显示磁盘分区d	显示磁盘挂载m	查看内存使用u	查看系统负载q	退出程序EOF
  1. 最终实现
#!/bin/bash
#打印菜单
cat <<-EOFh	显示命令帮助f	显示磁盘分区d	显示磁盘挂载m	查看内存使用u	查看系统负载q	退出程序EOF#让用户输入需要的操作
while true
do
read -p "请输入需要操作的选项[f|d]:" var1
case $var1 inh)cat <<-EOFh       显示命令帮助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
}
menu
while true
do
read -p "请输入你的操作[h for help]:" var1
case $var1 inh)menu;;f)read -p "请输入你要查看的设备名字[/dev/sdb]:" var2case $var2 in/dev/sda)fdisk -l /dev/sda;;/dev/sdb)fdisk -l /dev/sdb;;esac;;d)lsblk;;m)free -m;;u)uptime;;q)exit;;
esac
done

课堂练习:

  1. 输入一个等级(A-E),查看每个等级的成绩;如:输入A,则显示“90分~100分”,依次类推
  2. 判断用户输入的字符串,如果是"hello",则显示"world";如果是"world",则显示"hello",否则提示"请输入hello或者world,谢谢!"

二、函数

1. 什么是函数?

  • shell中允许将一组命令集合语句形成一段可用代码,这些代码块称为shell函数
  • 给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能

2. 如何定义函数?

方法1:

函数名()
{函数体(一堆命令的集合,来实现某个功能)   
}

方法2:

function 函数名()
{函数体(一堆命令的集合,来实现某个功能)echo helloecho world
}

函数中return说明:

  1. return可以结束一个函数。类似于循环控制语句break(结束当前循环,执行循环体后面的代码)。
  2. return默认返回函数中最后一个命令状态值,也可以给定参数值,范围是0-256之间。
  3. 如果没有return命令,函数将返回最后一个指令的退出状态值。

##3. 函数如何调用?

㈠ 当前命令行调用

[root@MissHou shell04]# cat fun1.sh 
#!/bin/bash
hello(){
echo "hello lilei $1"
hostname
}
menu(){
cat <<-EOF
1. mysql
2. web
3. app
4. exit
EOF
}[root@MissHou shell04]# source fun1.sh 
[root@MissHou shell04]# . fun1.sh [root@MissHou shell04]# hello 888
hello lilei 888
MissHou.itcast.cc
[root@MissHou shell04]# menu
1. mysql
2. web
3. app
4. exit

㈡ 定义到用户的环境变量中

[root@MissHou shell05]# vim ~/.bashrc 
文件中增加如下内容:
hello(){
echo "hello lilei $1"
hostname
}
menu(){
cat <<-EOF
1. mysql
2. web
3. app
4. exit
EOF
}注意:
当用户打开bash的时候会读取该文件

㈢ 脚本中调用

#!/bin/bash
#打印菜单
source ./fun1.sh
menu(){
cat <<-ENDh	显示命令帮助f	显示磁盘分区d	显示磁盘挂载m	查看内存使用u	查看系统负载q	退出程序END
}
menu		//调用函数

##4. 应用案例

具体需求:

  1. 写一个脚本收集用户输入的基本信息(姓名,性别,年龄),如不输入一直提示输入
  2. 最后根据用户的信息输出相对应的内容

思路:

  1. 交互式定义多个变量来保存用户信息 姓名、性别、年龄

  2. 如果不输一直提示输入

    • 循环直到输入字符串不为空 while 判断输入字符串是否为空
    • 每个信息都必须不能为空,该功能可以定义为一个函数,方便下面脚本调用
  3. 根据用户输入信息做出匹配判断

代码实现:

#!/bin/bash
#该函数实现用户如果不输入内容则一直循环直到用户输入为止,并且将用户输入的内容打印出来
input_fun()
{input_var=""output_var=$1while [ -z $input_var ]doread -p "$output_var" input_vardoneecho $input_var
}input_fun 请输入你的姓名:或者
#!/bin/bash
fun()
{read -p "$1" varif [ -z $var ];thenfun $1elseecho $varfi
}#调用函数并且获取用户的姓名、性别、年龄分别赋值给name、sex、age变量
name=$(input_fun 请输入你的姓名:)
sex=$(input_fun 请输入你的性别:)
age=$(input_fun 请输入你的年龄:)#根据用户输入的性别进行匹配判断
case $sex inman)if [ $age -gt 18 -a $age -le 35 ];thenecho "中年大叔你油腻了吗?加油"elif [ $age -gt 35 ];thenecho "保温杯里泡枸杞"elseecho "年轻有为。。。"fi;;woman)xxx;;*)xxx;;
esac

扩展延伸:

描述以下代码含义:	
:()
{:|:&
}
:

#三、综合案例

1. 任务背景

现有的跳板机虽然实现了统一入口来访问生产服务器,yunwei用户权限太大可以操作跳板机上的所有目录文件,存在数据被误删的安全隐患,所以希望你做一些安全策略来保证跳板机的正常使用。

2. 具体要求

  1. 只允许yunwei用户通过跳板机远程连接后台的应用服务器做一些维护操作
  2. 公司运维人员远程通过yunwei用户连接跳板机时,跳出以下菜单供选择:
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
  1. 当用户选择相应主机后,直接免密码登录成功
  2. 如果用户不输入一直提示用户输入,直到用户选择退出

3. 综合分析

  1. 将脚本放到yunwei用户家目录里的.bashrc文件里(/shell05/jumper-server.sh)
  2. 将菜单定义为一个函数[打印菜单],方便后面调用
  3. 用case语句来实现用户的选择【交互式定义变量】
  4. 当用户选择了某一台服务器后,进一步询问用户需要做的事情 case…esac 交互式定义变量
  5. 使用循环来实现用户不选择一直让其选择
  6. 限制用户退出后直接关闭终端 exit

4. 落地实现

#!/bin/bash
# jumper-server
# 定义菜单打印功能的函数
menu()
{
cat <<-EOF
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exitEOF
}
# 屏蔽以下信号
trap '' 1 2 3 19
# 调用函数来打印菜单
menu
#循环等待用户选择
while true
do
# 菜单选择,case...esac语句
read -p "请选择你要访问的主机:" host
case $host in1)ssh root@10.1.1.1;;2)ssh root@10.1.1.2;;3)ssh root@10.1.1.3;;h)clear;menu;;q)exit;;
esac
done将脚本放到yunwei用户家目录里的.bashrc里执行:
bash ~/jumper-server.sh
exit

进一步完善需求

为了进一步增强跳板机的安全性,工作人员通过跳板机访问生产环境,但是不能在跳板机上停留。

#!/bin/bash
#公钥推送成功
trap '' 1 2 3 19
#打印菜单用户选择
menu(){
cat <<-EOF
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
EOF
}#调用函数来打印菜单
menu
while true
do
read -p "请输入你要选择的主机[h for help]:" host#通过case语句来匹配用户所输入的主机
case $host in1|DB1)ssh root@10.1.1.1;;2|DB2)ssh root@10.1.1.2;;3|web1)ssh root@10.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 |awk

2. 正则能干什么?

  1. 匹配邮箱、匹配身份证号码、手机号、银行卡号等
  2. 匹配某些特定字符串,做特定处理等等

3. 正则当中名词解释

  • 元字符

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

  • 前导字符

    位于元字符前面的字符. ab**c*** aoo**o.**

##4. 第一类正则表达式

㈠ 正则中普通常用的元字符

元字符功能备注
.匹配除了换行符以外的任意单个字符
*前导字符出现0次或连续多次
.*任意长度字符ab.*
^行首(以…开头)^root
$行尾(以…结尾)bash$
^$空行
[]匹配括号里任意单个字符或一组单个字符[abc]
[^]匹配不包含括号里任一单个字符或一组单个字符[^abc]
1匹配以括号里任意单个字符或一组单个字符开头2
^[^]匹配不以括号里任意单个字符或一组单个字符开头^[^abc]
  • 示例文本
# cat 1.txt
ggle
gogle
google
gooogle
goooooogle
gooooooogle
taobao.com
taotaobaobao.comjingdong.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.2541)vim编辑器支持正则表达式
# vim 1.txt
:%s#\(10.1.1\).1#\1.254#g 
:%s/\(10.1.1\).1/\1.254/g 2)sed支持正则表达式【后面学】
# sed -n 's#\(10.1.1\).1#\1.254#p' 1.txt
10.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.txt 
hellolilei myself# sed -n 's/helloworld yourself/hellolilei myself/p' 1.txt 
hellolilei myself
# sed -n 's/\(hello\)world your\(self\)/\1lilei my\2/p' 1.txt 
hellolilei myselfPerl内置正则:
\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 'o+gle' 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.txt 
10.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.txt 
10.1.1.1
# grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' 1.txt 
10.1.1.1
# grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}' 1.txt 
10.1.1.1

##5. 第二类正则

表达式功能示例
[:alnum:]字母与数字字符[[:alnum:]]+
[:alpha:]字母字符(包括大小写字母)[[:alpha:]]{4}
[:blank:]空格与制表符[[:blank:]]*
[:digit:]数字[[:digit:]]?
[:lower:]小写字母[[:lower:]]{4,}
[:upper:]大写字母[[:upper:]]+
[:punct:]标点符号[[:punct:]]
[:space:]包括换行符,回车等在内的所有空白[[:space:]]+
[root@server shell05]# grep -E '^[[:digit:]]+' 1.txt
[root@server shell05]# grep -E '^[^[:digit:]]+' 1.txt
[root@server shell05]# grep -E '[[:lower:]]{4,}' 1.txt

6. 正则表达式总结

把握一个原则,让你轻松搞定可恶的正则符号:

  1. 我要找什么?
    • 找数字 [0-9]
    • 找字母 [a-zA-Z]
    • 找标点符号 [[:punct:]]
  2. 我要如何找?看心情找
    • 以什么为首 ^key
    • 以什么结尾 key$
    • 包含什么或不包含什么 [abc] ^[abc] [^abc] ^[^abc]
  3. 我要找多少呀?
    • 找前导字符出现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]
3匹配以括号里的任意单个字符开头4
^[^]不匹配以括号里的任意单个字符开头
^行的开头^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.txt 
Aieur45869Root0000
9h847RkjfkIIIhello
rootHllow88000dfjj
8ikuioerhfhupliooking
hello world
192.168.0.254
welcome to uplooking.
abcderfkdjfkdtest
rlllA899kdfkdfj
iiiA848890ldkfjdkfj
abc
12345678908374
123456@qq.com
123456@163.com
abcdefg@itcast.com23ed

2. 具体要求

1、查找不以大写字母开头的行(三种写法)。
grep '^[^A-Z]' 2.txt
grep -v '^[A-Z]' 2.txt
grep '^[^[:upper:]]' 2.txt
2、查找有数字的行(两种写法)
grep '[0-9]' 2.txt
grep -P '\d' 2.txt
3、查找一个数字和一个字母连起来的
grep -E '[0-9][a-zA-Z]|[a-zA-Z][0-9]' 2.txt
4、查找不以r开头的行
grep -v '^r' 2.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 -E 'A[0-9]{3}' 2.txt
grep  'A[0-9]\{3\}' 2.txt
12、统计root在/etc/passwd里出现了几次
grep -o 'root' 1.txt |wc -l13、用正则表达式找出自己的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-eth0
IPADDR=10.1.1.1
NETMASK=255.255.255.0
GATEWAY=10.1.1.254# egrep --color '[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}' /etc/sysconfig/network-scripts/ifcfg-eth0 
IPADDR=10.1.1.1
NETMASK=255.255.255.0
GATEWAY=10.1.1.25414、找出文件中的ip地址并且打印替换成172.16.2.254
grep -o -E '([0-9]{1,3}\.){3}[0-9]{1,3}' 1.txt |sed -n 's/192.168.0.\(254\)/172.16.2.\1/p'15、找出文件中的ip地址
grep -o -E '([0-9]{1,3}\.){3}[0-9]{1,3}' 1.txt16、找出全部是数字的行
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, --regexp=PATTERN      use PATTERN for matching-f, --file=FILE           obtain PATTERN from FILE-i, --ignore-case         忽略大小写-w, --word-regexp         匹配整个单词

#七、课后作业

脚本搭建web服务

要求如下

  1. 用户输入web服务器的IP、域名以及数据根目录
  2. 如果用户不输入则一直提示输入,直到输入为止
  3. 当访问www.test.cc时可以访问到数据根目录里的首页文件“this is test page”

参考脚本:

参考:
#!/bin/bash
conf=/etc/httpd/conf/httpd.conf
input_fun()
{input_var=""output_var=$1while [ -z $input_var ]doread -p "$output_var" input_vardoneecho $input_var
}
ipaddr=$(input_fun "Input Host ip[192.168.0.1]:")
web_host_name=$(input_fun "Input VirtualHostName [www.test.cc]:")
root_dir=$(input_fun "Input host Documentroot dir:[/var/www/html]:")[ ! -d $root_dir ] && mkdir -p $root_dir
chown apache.apache $root_dir && chmod 755 $root_dir
echo this is $web_host_name > $root_dir/index.html
echo "$ipaddr $web_host_name" >> /etc/hosts[ -f $conf ] && cat >> $conf <<end
NameVirtualHost $ipaddr:80
<VirtualHost $ipaddr:80>ServerAdmin webmaster@$web_host_nameDocumentRoot $root_dirServerName $web_host_nameErrorLog logs/$web_host_name-error_logCustomLog logs/$web_host_name-access_loh common
</VirtualHost>
end

  1. ↩︎

  2. abc ↩︎

  3. ↩︎

  4. abc ↩︎

相关文章:

shell编程之循环语句

typora-copy-images-to: pictures typora-root-url: …\pictures 文章目录typora-copy-images-to: pictures typora-root-url: ..\..\pictures一、for循环语句1. for循环语法结构㈠ 列表循环㈡ 不带列表循环㈢ 类C风格的for循环2. 应用案例㈠ 脚本计算1-100奇数和① 思路② 落地…...

神经动力学-第一章-神经动力学基础-神经系统的元素

神经元和数学 本章的主要目的是介绍神经科学的几个基本概念,尤其是动作电位、突触后电位、触发阈值、不应期和适应性。基于这些概念,建立了神经元动力学的初步模型,这个简单的模型(漏积分-火模型)将作为本书主题——广义积分-火模型的起点和参考,在第二部分和第三部分进…...

【力扣-LeetCode】64. 最小路径和 C++题解

64. 最小路径和难度中等1430收藏分享切换为英文接收动态反馈给定一个包含非负整数的 m x n 网格 grid &#xff0c;请找出一条从左上角到右下角的路径&#xff0c;使得路径上的数字总和为最小。说明&#xff1a;每次只能向下或者向右移动一步。示例 1&#xff1a;输入&#xff…...

Mysql数据库事务

数据库事务 数据库事务由一组sql语句组成。 所有sql语句执行成功则事务整体成功&#xff1b;任一条sql语句失败则事务整体失败&#xff0c;数据恢复到事务之前的状态。 Mysql 事务操作 开始事务 start transaction;- 或 begin;事务开始后&#xff0c;对数据的增删改操作不…...

【opencv源码解析0.3】调试opencv源码的两种方式

调试opencv源码的两种方式 上两篇我们分别讲了如何配置opencv环境&#xff0c;以及如何编译opencv源码方便我们阅读。但我们还是无法调试我们的代码&#xff0c;无法以我们的程序作为入口来一步一步单点调试看opencv是如何执行的。 【opencv源码解析0.1】VS如何优雅的配置ope…...

Xcode Archives打包上传 / 导出ipa 发布至TestFlight

Xcode自带的Archives工具可以傻瓜式上传到App Store Connect分发这里以分发到TestFlight为例进行操作。 环境&#xff1a;Xcode 14 一&#xff1a;Archives打包 选择Xcode菜单栏的Product&#xff0c;Archives选项&#xff0c;需要等待编译完成&#xff0c;进入如下界面&…...

RNN GRU模型 LSTM模型图解笔记

RNN模型图解引用RNN模型GRULSTM深度RNN双向循环神经网络引用 动手学深度学习v2–李沐 LSTM长短期记忆网络3D模型–B站up梗直哥丶 RNN模型 加入了一个隐变量&#xff08;状态)&#xff0c;隐变量由上个隐变量和上一个输入而更新&#xff0c;这样模型就可以达到具有短期记忆的效…...

西电_数字信号处理二_学习笔记

文章目录【 第1章 离散随机信号 】【 第2章 维纳滤波 】【 第3章 卡尔曼滤波 】【 第4章 自适应滤波 】【 第5章 功率谱估计 】这是博主2022秋季所学数字信号处理二的思维导图&#xff08;软件是幕布&#xff09;&#xff0c;供大家参考&#xff0c;如内容上有不妥之处&#xf…...

[ vulhub漏洞复现篇 ] Drupal 远程代码执行漏洞(CVE-2018-7602)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…...

MySQL最佳实践

一、MySQL查询执行过程 1.MySQL分层结构 MySQL8.0没有查询缓存的功能了,如果频繁修改缓存,将会损耗性能查询流程就按照分层结构就可以清楚,只要了解各个组件的各自功能就行分析器主要分析语法和词法是否正确优化器主要优化SQL语句 二、MySQL更新执行过程 更新主要涉及两个重…...

Python 之 Matplotlib 散点图、箱线图和词云图

文章目录一、散点图1. scatter() 函数2. 设置图标大小3. 自定义点的颜色和透明度4. 可以选择不同的颜色条&#xff0c;配合 cmap 参数5. cmap 的分类5.1 Sequential colormaps&#xff1a;连续化色图5.2 Diverging colormaps&#xff1a;两端发散的色图 .5.3 Qualitative color…...

SpringCloud(三)Hystrix断路器服务降级、服务熔断、服务监控案例详解

七、Hystrix断路器 7.1 简介 分布式系统面临的问题 复杂分布式体系结构中的应用程序有数十个依赖关系&#xff0c;每个依赖关系在某些时候将不可避免地失败。 多个微服务之间调用的时候&#xff0c;假设微服务A调用微服务B和微服务C&#xff0c;微服务B和微服务C又调用其它的微…...

【超好用】自定义的mybatis-plus代码生成器

BACKGROUND你是否也有这样的烦恼&#xff1a;每次写代码都需要创建很多包很多层很多类很多接口&#xff1f;耗时且费力姑且不谈&#xff0c;有时可能还大意了没有闪&#xff0c;搞出一堆bug这谁顶得住啊都3202年了&#xff0c;让程序自力更生吧&#xff01;&#xff01;教程 le…...

Kubernetes学习笔记-计算资源管理(4)监控pod的资源使用量20230219

前面学了设置资源的requests和limits&#xff0c;这节课学习如何监控资源&#xff0c;根据监控资源使用情况&#xff0c;对requests和limits进行合理配置。收集、获取实际资源使用情况kubelet包含一个agent&#xff0c;名为cAdvisor&#xff0c;它会收集整个节点上运行的所有单…...

游戏开发 - 开发流程 - 收集

1.应用场景 主要用于了解&#xff0c;掌握游戏开发的整个流程。 2.学习/操作 1.文档阅读 复习课 | 带你梳理客户端开发的三个重点-极客时间 2.整理输出 2.1 游戏开发流程 -- 参考 按照游戏开发中的三大模块策划、程序、美术&#xff0c;画了一个图。 开发游戏的时候&#xff…...

LA@向量空间@坐标变换

文章目录向量空间向量空间的属性坐标例基变换坐标变换n维向量空间RnR^nRn子空间例线性组合与线性方程组生成子空间深度学习向量空间 设VVV是n维向量的非空集合,如果VVV对向量的加法和数乘运算封闭,即 ∀α,β∈V,∀k∈Rαβ,kα∈V\forall \alpha,\beta\in{V},\forall k\in{\ma…...

JSP脚本指令及标记学习笔记

好久没更新文章了&#xff0c;上次更新的文章还是一个学习笔记。本篇博文介绍的是JSP基本概念 1.JSP开发方法 一个jsp网页只需要加上<%%>就行了。 2.JSP运行机制 3.JSP脚本元素 3.1 JSP脚本代码 <% 脚本代码 %>实例 <% SimpleDateFormat df new SimpleDa…...

【C语言每日一题】——猜凶手

【C语言每日一题】——猜名次&#x1f60e;前言&#x1f64c;猜凶手&#x1f64c;解题思路分享&#xff1a;&#x1f60d;解题源码分享&#xff1a;&#x1f60d;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神…...

2019蓝桥杯真题完全二叉树的权值 C语言/C++

题目描述 给定一棵包含 N个节点的完全二叉树&#xff0c;树上每个节点都有一个权值&#xff0c;按从 上到下、从左到右的顺序依次是 A_1, A_2, A_N&#xff0c;如下图所示&#xff1a; 现在小明要把相同深度的节点的权值加在一起&#xff0c;他想知道哪个深度的节点 权值之和最…...

大数据之Phoenix环境搭建

文章目录前言一、下载Phoenix安装包二、上传并解压三、拷贝服务包到各个hbase的lib目录下四、修改hbase的配置文件五、重启HBase集群六、连接Phoenix客户端前言 #博学谷IT学习技术支持# 本篇文章主要介绍Phoenix的环境搭建&#xff0c;Phoenix支持使用SQL语句操作HBase&#x…...

7.2.1_顺序查找

知识总览&#xff1a; 顺序查找&#xff1a; 算法思想&#xff1a; 从头到脚挨个找或者从脚到头挨个找适用于线性表(顺序存储和链式存储都适用)&#xff0c;又叫线性查找 实现&#xff1a; 1个数组elem指向数组的起始位置&#xff0c;索引从0开始遍历数组直到找到目标值返回…...

软件工程:如何做好软件产品

1、什么是产品 从项目到产品 产品&#xff1a;满足行业共性需求的标准产品。即要能够做到配置化的开发&#xff0c;用同一款产品最大限度地满足不同客户的需求&#xff0c;同时让产品具有可以快速响应客户需求变化的能力。 好的产品一定吸收了多个项目的共性&#xff0c;一定是…...

Spring AI之RAG入门

目录 1. 什么是RAG 2. RAG典型应用场景 3. RAG核心流程 3.1. 检索阶段 3.2. 生成阶段 4. 使用Spring AI实现RAG 4.1. 创建项目 4.2. 配置application.yml 4.3. 安装ElasticSearch和Kibana 4.3.1. 安装并启动ElasticSearch 4.3.2. 验证ElasticSearch是否启动成功 …...

逻辑回归与Softmax

Softmax函数是一种将一个含任意实数的K维向量转化为另一个K维向量的函数,这个输出向量的每个元素都在(0, 1)区间内,并且所有元素之和等于1。 因此,它可以被看作是某种概率分布,常用于多分类问题中作为输出层的激活函数。这里我们以拓展逻辑回归解决多分类的角度对Softmax函…...

让敏感数据在流转与存储中始终守护在安全范围

在企业数字化运营浪潮中&#xff0c;企业内部应用服务器面临着非法访问、数据泄露等风险&#xff0c;如何全面守护应用服务器文件安全&#xff0c;让敏感数据在流转与存储中始终守护在安全范围&#xff1f; 服务器白名单让数据流转安全又高效 天 锐 蓝盾的服务器白名单功能既…...

CppCon 2015 学习:Functional Design Explained

这两个 C 程序 不完全相同。它们的差异在于对 std::cout 的使用和代码格式。 程序 1&#xff1a; #include <iostream> int main(int argc, char** argv) {std::cout << "Hello World\n"; }解释&#xff1a;这个程序是 正确的。std::cout 是 C 标准库中…...

JavaEE->多线程:定时器

定时器 约定一个时间&#xff0c;时间到了&#xff0c;执行某个代码逻辑&#xff08;进行网络通信时常见&#xff09; 客户端给服务器发送请求 之后就需要等待 服务器的响应&#xff0c;客户端不可能无限的等&#xff0c;需要一个最大的期限。这里“等待的最大时间”可以用定时…...

resolvers: [ElementPlusResolver()] 有什么用?

resolvers: [ElementPlusResolver()] 是配合特定自动化导入插件&#xff08;如 unplugin-vue-components 和 unplugin-auto-import&#xff09;使用的配置项&#xff0c;其核心作用是‌实现 Element Plus 组件库的按需自动导入‌。 具体来说&#xff1a; 自动导入组件 (对应 …...

【设计模式-3.4】结构型——代理模式

说明&#xff1a;说明&#xff1a;本文介绍结构型设计模式之一的代理模式 定义 代理模式&#xff08;Proxy Pattern&#xff09;指为其他对象提供一种代理&#xff0c;以控制对这个对象的访问&#xff0c;属于结构型设计模式。&#xff08;引自《设计模式就该这样学》P158&am…...

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Sound Board(音响控制面板)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— SoundBoard 组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ &#x1f3af; 组件目标 实现一个响应式按钮面板&#xff0c;点…...