08·Shell编程-循环

2022-09-26 10:36:45 浏览数 (1)

  • 循环的基本概述
    • 循环分类
    • while循环介绍
    • until循环(忘记)
    • for循环
  • 循环控制语句
    • break 跳出循环
    • continue 跳出循环
  • 循环读取文件内容
  • 日志分析案例
  • 面试题案例

-曾老湿, 江湖人称曾老大。


-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。


循环的基本概述

循环分类

循环名称

循环含义

使用场景

while循环

当型循环

死循环/有条件的循环/一行一行的读取文件

do until循环

直到型循环,一直循环直到不满足条件

没啥场景,因为有for循环

for循环

通用型

很多场景都可以使用

while循环介绍

while循环语法

代码语言:javascript复制
while <条件表达式>;do
  cmd1
  cmd2
done

while <条件表达式>
do
  cmd1
  cmd2
done

while 没有女朋友;do
  找到死
done

while 话费充足;do
  打电话
done

## 死循环
while true;do
  echo 'hei hei hei'
done

while [ 1 -eq 1 ];do 
  echo 'hei hei hei'
done

while :;do
  echo 'hei hei hei'
done

使用while模拟seq

代码语言:javascript复制
#!/bin/bash

i=1
while [ $i -le 10 ];do
    echo $i
    ((i  ))
done

[root@zabbix01 ~]# sh seq.sh
1
2
3
4
5
6
7
8
9
10

使用while从1加到100

代码语言:javascript复制
#!/bin/bash

i=1
num=0
while [ $i -le 100 ];do
  ((num=num i))
  ((i  ))
done

echo $num


## 如果你对命令很精通,那么其实一条命令可以完成这个循环。

[root@zabbix01 ~]# echo {1..100}|tr ' ' ' '|bc
5050

[root@zabbix01 ~]# seq -s  100|bc
5050

[root@zabbix01 ~]# seq 100|awk '{sum=sum $1}END{print sum}'
5050

[root@zabbix01 ~]# awk 'BEGIN{for(i=1;i<=100;i  )sum=sum i;print sum}'
5050

until循环(忘记)

until循环语法

until 循环执行一系列命令直至条件为 true 时停止。

until 循环与 while 循环在处理方式上刚好相反。

一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

代码语言:javascript复制
until <条件表达式>;do
  cmd1
done


until 话费是否充足;do
  打电话
done

看一眼,忘了就完事,用不着。

for循环

for循环语法

  • 语法一:

无法指定循环次数,表达式有多少内容就循环多少次

代码语言:javascript复制
for var in 变量表达式;do
  cmd1
  cmd2
done

for var in 变量表达式
do
  cmd1
  cmd2
done

# 变量表达式:
1.可以是以空格为分隔符的字符串
2.可以是以空格为分隔符的数字
3.可以是数组
4.可以是命令结果
5.可以是文件内容(但是要注意for并不是按行读取,如果每一行都没有空格还行,但是一旦遇到空格就...)

# 例:
## 循环以空格为分隔符的字符串
for name in "zls cls wls";do
  echo $name
done

## 循环以空格为分隔符的数字
for num in 1 2 3 4 5;do
  echo $num
done

for num in {1..10};do
  echo $num
done

for zm in {a..z};do
  echo $zm
done

## 循环数组
array=("zls" "cls" "wls" "boduols")
for str in ${array[@]};do
  echo $str
done

##  循环命令结果
for file in `ls -1 /`;do
  echo $file
done

for text in `cat /etc/passwd`;do
  echo $text
done
  • 语法二:

可指定循环次数格式

代码语言:javascript复制
for((i=1;i<=10;i  ));do
  echo $i
done

for也可以无限循环

代码语言:javascript复制
for (( ; ; ));do
  echo 123
done

循环控制语句

break 跳出循环

break命令允许跳出所有循环(终止执行后面的所有循环)。

下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。

代码语言:javascript复制
[root@zabbix01 ~]# vim break.sh
#!/bin/bash

while true;do
  read -p 'Please Input A Number: ' num
  if [ $num -ne 5 ];then
      echo "你输入的是 $num"
  else
      break
  fi
done


[root@zabbix01 ~]# sh break.sh
Please Input A Number: 1
你输入的是 1
Please Input A Number: 2
你输入的是 2
Please Input A Number: 3
你输入的是 3
Please Input A Number: 4
你输入的是 4
Please Input A Number: 5

continue 跳出循环

continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

代码语言:javascript复制
#!/bin/bash

while true;do
  read -p 'Please Input A Number: ' num
  if [ $num -ne 5 ];then
      echo "你输入的是 $num"
  else
      continue
  fi
done

[root@zabbix01 ~]# sh continue.sh
Please Input A Number: 1
你输入的是 1
Please Input A Number: 2
你输入的是 2
Please Input A Number: 3
你输入的是 3
Please Input A Number: 4
你输入的是 4
Please Input A Number: 5
Please Input A Number: 6
你输入的是 6
Please Input A Number: 7
你输入的是 7

循环读取文件内容


while读取文件内容

代码语言:javascript复制
## 方法一:使用exec读取文件内容,然后进入while循环
[root@zabbix01 ~]# cat student.txt
曾老湿
苍井空
武藤兰
天海翼
西野翔
        
[root@zabbix01 ~]# vim while.sh       

#!/bin/bash

exec < student.txt

while read name;do
  echo $name
  echo "------"
done

[root@zabbix01 ~]# sh while.sh
曾老湿
------
苍井空
------
武藤兰
------
天海翼
------
西野翔
------


## 方法二:使用管道符,将文件内容交给while循环
cat student.txt|while read line_name;do

  echo $line_name
  echo "------"
done

## 方法三:使用标准输入,将文件内容交给while循环
#!/bin/bash 

while read name;do
  echo $name
  echo "------"
done < student.txt

while读文件练习

写一个脚本,读取下面文件内容,并算出所有人年龄总和

代码语言:javascript复制
[root@zabbix01 ~]# cat student.txt
曾老湿 18
苍井空 20
武藤兰 33
天海翼 32
西野翔 18

日志分析案例

写一个shell脚本,防止DDOS攻击,先分析日志,监控某一个IP并发连接数,若短时内PV达到100阈值,则调用防火墙命令,封掉该IP。

可以分析nginx日志或者查看当前网络连接数 ss -ant 或者 netstat -ant

这里使用一个生产的日志 netstat.log

面试题案例


生成随机文件名

在指定目录下,通过随机10个小写字母,然后生成一个文件名为:随机字母_zls.txt的文件

生成随机内容的方法

代码语言:javascript复制
## 方法一:
[root@zabbix01 ~]# openssl rand -base64 10
UUBtKUvUkEfcEw==

## 方法二:
[root@zabbix01 ~]# echo $((RANDOM))|md5sum

## 方法三:
[root@zabbix01 ~]# date  %N|md5sum
3fd3a5c57def5f89481e1961fceb13e8

## 方法四:
tr -cd 'a-zA-Z0-9'</dev/urandom|head -c 10

批量修改文件名

代码语言:javascript复制
 # 提示一:变量子串方法
 
 # 提示二:sed awk方法
 
 # 提示三:命令拼接
 
 # 提示四:rename
 rename zls.txt cls.TXT /root/*.txt

批量创建系统用户设置8位随机密码

之前我们使用的awk命令拼接的方式

代码语言:javascript复制
[root@zabbix01 ~]# seq 5|awk '{print "pass=echo 123|md5sum|cut -c 1-8;useradd zls"$1";echo $pass|tee -a /tmp/pass.log|passwd --stdin zls"$1}'

扫描网段内,存活的主机

现在我们要模拟黑客,来扫描,指定网段内存活的主机

代码语言:javascript复制
## 方法一:在没有学习任何攻防命令的情况下,我们可以使用for循环
for n in `seq 255`;do
  ping 10.0.0.$n
done


# 优化

for n in `seq 255`;do
  ping -c1 -W1 -i1 10.0.0.$n &>/dev/null
  if [ $? -eq 0 ];then
    echo 10.0.0.$n is ok
  fi
done

## 专业点
. /etc/init.d/functions

for n in `seq 255`;do
{
  ping -c1 -W1 -i1 10.0.0.$n &>/dev/null
  if [ $? -eq 0 ];then
    action 10.0.0.$n /bin/true
  fi
} &
done

# 并发执行
for n in `seq 255`;do
{
  ping -c1 -W1 -i1 10.0.0.$n &>/dev/null
  if [ $? -eq 0 ];then
    echo 10.0.0.$n is ok
  fi
} &
done

## 并发执行bug解决
. /etc/init.d/functions

for n in `seq 255`;do
{
  ping -c1 -W1 -i1 10.0.0.$n &>/dev/null
  if [ $? -eq 0 ];then
    action 10.0.0.$n /bin/true
  fi
} &
usleep 200
done

## 方法二:nmap  简单粗暴
nmap 10.0.0.0/24
nmao -n -sn 10.0.0.0/24

欢迎界面优化

figlet

代码语言:javascript复制
[root@zabbix01 ~]# figlet zls

[root@zabbix01 ~]# showfigfonts

[root@zabbix01 ~]# figlet zls -f banner

[root@zabbix01 ~]# watch -n1 "date  %D%n%T|figlet -k"

0 人点赞