Shell编程实践

Shell编程实践

  • 第三个阶段 ( Shell 8天内容 Shell脚本编写、正则表达式、grep、sed、awk)
    • Shell脚本
    • Git、Gitlab、Jenkins
    • Zabbix

1.Shell内容大纲

  • 1.shell基本概述

    • 1.什么是Shell
    • 2.什么是Shell脚本
    • 3.Shell的应用场景
    • 4.如何学习Shell脚本
  • 2.shell变量定义variables

    • 1.自定义变量
    • 2.环境变量
    • 3.预定义变量
    • 4…等等
  • 3.shell数值运算expr bc

  • 4.shell流程控制if case

  • 6.shell循环语句for while

  • 7.shell数组函数array function

  • 8.shell内置命令break continue exit

2.Shell基本介绍

  • 1.shell介绍

    • shell是一个命令解释器,主要用来接收用户的指令,进入驱动操作系统,或硬件。
  • 2.shell存在交互和非交互 ( 创建100个用户 )

    • 交互:登陆Linux、useradd、passwd ( 重复100次 )
    • 非交互: 创建100个用户的操作写入至一个文件中,然后去执行。( 全程不需要用户参与 )
  • 3.什么是shell脚本

    1. 将系统命令堆积在一起,顺序执行(简称: 系统命令堆积)
    2. 特定的格式 + 特定的语法 + 系统的命令 = 文件 ( Shell脚本文件)。
#!/usr/bin/bash							#特定的格式

for i in {1..100}						#特定的语法
do
	useradd oldboy{1..10}			#系统的命令
done	

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iouxM8pm-1594120060748)(Shell编程实践.assets/image-20200603093728772.png)]

3.学习Shell预备知识

  • 1.熟练使用vim编辑器 ()
  • 2.熟练使用系统基础命令 ( useradd、w、awk、…)
  • 3.熟悉Linux、grep、awk、sed
  • 注意:命令不熟、基本的服务连手动搭建都有困难,一定学不会Shell。

如何学好Shell?

​ 1.基础命令+基础服务+练习题+ ( 思路!!! )

​ 2.能看懂–>照抄着写–>能修改–>能编写–>能优化脚本

4.Shell书写方式

  • 1.Shell脚本名称必须要有含义 a.sh、b.sh、建议命名的方式最好在30个字节以内解决。 check_memory.sh

  • 2.shell脚本的格式 (建议在文件的首行添加 #!/bin/bash、#!/usr/bin/bash )

  • 3.shell脚本建议添加一些个注释

#!/usr/bin/bash   #申明系统在执行时使用bash解释器翻译该文件的内容
# Author: wenjie、[email protected]
# Create Time 2020/06/03
# Script Description: 这个脚本是用来检查系统内存使用情况。

# 所有的注释可以自动生成,大家可以研究一下。vimrc

5.Shell执行方式

添加 #!/bin/bash 的作用。

  • 1.不添加
    • 默认 ./运行时,系统会调bash来运行该脚本。
    • 缺点:如果我写的是python脚本,直接调用bash来运行则会报错。
  • 2.添加
    • ./运行脚本,默认会读取该文件第一行,来确定使用什么解释器运行。
  • 3.直接调用解释器运行 ( 无需在意文件首行指定的解释器 )
    • python check_shell.sh
    • bash check_shell.sh #日常使用最多( 我确定他是一个shell脚本,所以我会选择直接使用bash解释器翻译该脚本文件 )

6.Shell变量

  • 1.什么是变量

  • 变量其实是Shell传递数据的一种方式。以一个固定的字符串去表示一个不固定的值。便于后续的复用,以及维护。

  • 2.变量的命名规范 ( 熟悉 )

    • 变量命令规范:大小写、下划线拼接变量名、尽量字母开头。( 变量最好有含义,如果没有,容易忘记这个变量是做什么的。 )
    • 变量如何定义: 变量名=变量值,等号是赋值。 a=123 a变量 123值
    • 变量定义参考:
    ip=10.0.0.1								#小写,会容易与系统的命令冲突
    ip1=10.0.0.1							#小写+数字
    Hostname_Ip=10.0.0.1			#驼峰式命名   大写开头小写结束_大写开头_小写结束
    Hostname_IP=10.0.0.1			#开头大写,_后面全大写
    
    # ”变量名称“ 首字母大写的原因是为了避免与系统的命令产生冲突。
    
  • 3.变量定义的几种方式 ( 使用61服务器 )

    • 1.用户自定义变量,自己随意定义变量。

    • [root@web01 ~]# var="hello world"		#定义变量 ( 等号两边没有空格 )
      [root@web01 ~]# echo $var					  #$变量名   ${变量名}
      hello world
      
      #使用$变量名   ${变量名} 区别?
      [root@web01 ~]# echo $var_log
      
      [root@web01 ~]# echo ${var}_log
      hello world_log
      
      # 单引号和双引号的区别?
      [root@web01 ~]# var2=Iphone
      [root@web01 ~]# echo "$var2 is good"		#双引号会解析中的$符号
      Iphone is good
      
      [root@web01 ~]# echo '$var2 is good'		#写什么就是什么
      $var2 is good
      
      
      #什么时候使用 单引号和双引号:
      	如果你输出的结果中包含变量名需要解析,则建议使用双引号。
      	如果你输出的结果仅仅只是一个字符串,但里面存在特殊字符,那么你可以选择使用单引号。
      
    • 2.系统环境变量,保存的是和系统操作环境相关的,所有用户都可以调用。

    • #系统已经定义好了一些个变量,供我们使用。(所有的用户都可以使用)
      
      

[root@web01 ~]# cat check_env.sh
#!/bin/bash
##############################################################
# File Name: chech_env.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

echo "用户的家目录: $HOME"
echo "当前主机名是: $HOSTNAME"
echo "当前所在目录: $PWD"
echo "当前SSH连接: $SSH_CONNECTION"


​ [root@web01 ~]# cat get_system_info.sh
​ #!/bin/bash
​ ##############################################################
​ # File Name: get_system_info.sh
​ # Author: wenjie
​ # Organization: [email protected]
​ ##############################################################

​ #如果执行该脚本的UID不为0,则提示没有权限,如果为0 则输出系统状态指标获取成功。 [ -ne 表示不等于 ]
​ if [ U I D − n e 0 ] ; t h e n ​ e c h o " UID -ne 0 ];then ​ echo " UIDne0];thenecho"USER 没有权限执行该脚本!!"
​ exit
​ fi
​ echo “系统状态指标获取完毕!!!”

​ #拷贝到其他普通用户测试
​ [root@web01 ~]# useradd oldg
​ [root@web01 ~]# cp get_system_info.sh /home/oldg/
​ [root@web01 ~]# su - oldg
​ [oldg@web01 ~]$ sh get_system_info.sh
​ oldg 没有权限执行该脚本!!
​ ```

  • 3.位置参数变量,向脚本进行传递参数的,变量名不能自定义,变量作用也是固定的。

  • #在执行脚本时,可以对脚本进行参数的传递。
    
    [root@web01 ~]# cat variables.sh
    #!/bin/bash
    ##############################################################
    # File Name: variables.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    #!/bin/bash
    echo "#当前shell脚本的文件名: $0"
    echo "#第1个shell脚本位置参数:$1"
    echo "#第2个shell脚本位置参数:$2"
    echo "#第3个shell脚本位置参数:$3"
    echo "#所有传递的位置参数是: $*"
    echo "#所有传递的位置参数是: $@"
    echo "#总共传递的参数个数是: $#"
    echo "#当前程序运行的 PID 是: $$"
    echo "#上一个命令执行的返回结果: $?"
    
    
    [root@web01 ~]# sh variables.sh 11 22 33 44
    #当前shell脚本的文件名: variables.sh
    #第1个shell脚本位置参数:11
    #第2个shell脚本位置参数:22
    #第3个shell脚本位置参数:33
    #所有传递的位置参数是: 11 22 33 44
    #所有传递的位置参数是: 11 22 33 44
    #总共传递的参数个数是: 4
    #当前程序运行的 PID 是: 4159
    #上一个命令执行的返回结果: 0
    
  • 4.练习

    • 需求1:通过位置变量创建 Linux 系统账户及密码,执行 var1.sh username password

    • [root@web01 ~]# cat create_user_1.sh
      #!/bin/bash
      ##############################################################
      # File Name: create_user_1.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      #1.添加用户
      useradd $1
      
      #为用户设定密码
      echo "$2" | passwd --stdin $1
      
      [root@web01 ~]# sh create_user_1.sh  oldxxx 123
      
    • 需求2:通过位置变量创建 Linux 系统账户及密码,执行 var1.sh username password,控制最多传递两个参数。【这个脚本仅root能执行,其他普通用户无法执行创建用户脚本。】

    • #1.如何知道他传递了多少个参数?					    $#
      #2.判断他传递的参数是否大于我想设定的参数?   if
          大于:则报错提示
          刚好:执行脚本
      
      [root@web01 ~]# cat create_user_2.sh
      #!/bin/bash
      ##############################################################
      # File Name: create_user_1.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      #1.判断他是什么用户身份在执行这个脚本
      if [ $UID -ne 0 ];then
          echo "$USER 用户你没有权限,请切到Root用户在执行"
          exit
      fi
      
      #2.判断用户传递的的参数是否满足2个
      if [ $# -ne 2 ];then
          echo "Please Input Parameters [ username &&  password ]"
          exit
      fi
      
      #3.添加用户
      useradd $1
      
      #4.为用户设定密码
      echo "$2" | passwd --stdin $1
      
  • 4.变量赋值的方式read (交互式传递变量)

[root@web01 ~]# cat read-1.sh
#!/bin/bash
##############################################################
# File Name: read-1.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

read -p "Login: " acc
read -p "Passwd: " pw
echo "login: $acc    passwd: $pw"



[root@web01 ~]# cat read-1.sh
#!/bin/bash
##############################################################
# File Name: read-1.sh
# Author: wenjie
# Organization: [email protected]
##############################################################


#-s 不回显,就是不显示输入的内容
#-n 指定字符个数
#-t 超时时间
read -p "Login: " acc
read -s -t10 -n6 -p "Passwd: " pw

echo "login: $acc    passwd: $pw"
  • read练习题:

    • 需求1:使用read模拟Linux登陆页面

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WD2GxmZD-1594120060752)(Shell编程实践.assets/image-20200603123018442.png)]

    • #1.你先得知道linux的登陆页面是啥样子的?
      [root@web01 ~]# cat read-2.sh
      #!/bin/bash
      ##############################################################
      # File Name: read-2.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      hostnamectl  | awk -F ':' '/System/ {print $2}'
      echo "Kernel $(uname -r) an $(uname -m)"
      echo ""
      read -p  "$(hostname) login: " acc
      read -s -p "Passwd: " pw
      echo ""
      echo "Login: $acc    Passwd: $pw"
      
    • 需求2:使用 read编写一个备份脚本,需要用户传递2个参数,源和目标。

    • 1.在执行脚本时,
      提示1:请填写需要备份的文件或目录路径:     /opt
      提示2:你希望备份到哪去:     /tmp
      ----action动作:
          cp  -rp /opt/ /tmp
          
          
          
      [root@web01 ~]# cat read-3.sh
      #!/bin/bash
      ##############################################################
      # File Name: read-3.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      
      read -p "你要备份的文件或目录路径是: " src
      read -p "你要备份到哪个目录下存储:" dest
      
      read -p "你确定将  $src  备份到  $dest 吗? [ y | n ]" action
      
      #判断用户输入的是y还是n,y则进行备份,n则提示没有备份
      if [ $action == "y" ];then
          echo "-----------备份开始--------------"
          cp -rp $src $dest
          sleep 3
          echo "-----------备份结束--------------"
      else
          echo "-----------备份退出--------------"
          exit
      fi
      
    • 需求3:使用 read编写一个探测主机存活脚本,需要用户传递测试的IP地址。 [并没有说使用传参,而是让其使用read的方式]

    • [root@web01 ~]# cat read-4.sh
      #!/bin/bash
      ##############################################################
      # File Name: read-4.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      #探测主机是否存活
      read -p "请输入你要探测的主机IP地址: " Ip
      ping -c2 $Ip &>/dev/null
      
      if [ $? -eq 0 ];then
          echo "$Ip 存活"
      else
          echo "$Ip 不存活"
      fi
      
    • 需求4:使用read编写一个修改系统主机名称脚本。【询问:是否修改,y修改、n退出脚本不修改】

脚本大概内容应该如下:
1.先输出当前系统的主机名称:  web01
2.询问需要修改为新的主机名称是什么?     test01
3.确定要将  web01 变更为  test01 吗?   [ y  | n ]    
4.判断用户输入的是y还是n
    y:使用hostnamectl 变更主机名称
    n:直接退出此脚本
    
[root@web01 ~]# cat read-5.sh
#!/bin/bash
##############################################################
# File Name: read-5.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

Old_Host=$(hostname)
echo "当前系统的主机名称是: ${Old_Host}"
read -p "你想修改的主机名称是: " New_Host
read -p "你确定要将  ${Old_Host} 变更为 ${New_Host} 名称吗? [ y | n ]" Action

if [ $Action == "y" ];then
    echo "------------------正在修改主机名称-------------------"
    hostnamectl set-hostname ${New_Host}
    sleep 1
    echo ""
    echo "-----------------主机名称修改完毕---------------------"
fi
  • 5.变量的替换

    • 在不改变原来变量的值情况下,进行变量的替换。

    • 什么时候会使用到?

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4KSN8I4t-1594120060755)(Shell编程实践.assets/image-20200603144955082.png)]

    • #和双##
      
      [root@web01 ~]# url=www.sina.com.cn
      [root@web01 ~]# echo ${url}
      www.sina.com.cn
      [root@web01 ~]# echo ${url#*.}		#从头开始匹配,然后删除
      sina.com.cn
      [root@web01 ~]# echo ${url#*.*.}
      com.cn
      
      [root@web01 ~]# echo ${url##*.}		#贪恋匹配模式
      cn
      
      # %和双%%
      [root@web01 ~]# echo ${url%.*}
      www.sina.com
      
      [root@web01 ~]# echo ${url%.*.*}
      www.sina
      
      [root@web01 ~]# echo ${url%%.*}
      www
      
      # / 与 //
      
      [root@web01 ~]# echo ${url}
      www.sina.com.cn
      [root@web01 ~]# echo ${url/sina/SINA}
      www.SINA.com.cn
      [root@web01 ~]# echo ${url//c/C}
      www.sina.Com.Cn
      
    • 1.希望把$PATH中的/bin全部都替换为 /BIN

      [root@web01 ~]# echo $PATH
      /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
      
      [root@web01 ~]# echo ${PATH//bin/BIN}
      /usr/local/sBIN:/usr/local/BIN:/usr/sBIN:/usr/BIN:/root/BIN
      

      2.习题2:

      需求2:变量string="Bigdata process is Hadoop, Hadoop is open source project",执行脚本后,打印输出string变量,并给出用户以下选项:
      1)、打印string长度
      2)、删除字符串中所有的Hadoop
      3)、替换第一个Hadoop为Linux
      4)、替换全部Hadoop为Linux
      用户输入数字1|2|3|4,可以执行对应项的功能,输入q|Q则退出交互模式
      
      [root@web01 ~]# cat vars.sh
      #!/bin/bash
      ##############################################################
      # File Name: vars.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      string="Bigdata process is Hadoop, Hadoop is open source project"
      
      echo "$string"
      cat <<EOF
      1)、打印string长度
      2)、删除字符串中所有的Hadoop
      3)、替换第一个Hadoop为Linux
      4)、替换全部Hadoop为Linux
      EOF
      read -p "请输入你想执行的操作 [ 1 | 2 | 3 | 4 | q ] " Action
      
      if [ $Action -eq 1 ];then
          echo "String变量的长度是: ${#string}"
      fi
      
      if  [ $Action -eq 2 ];then
          echo ${string//Hadoop/}
      fi
      
      if [ $Action -eq 3 ];then
              echo ${string/Hadoop/Linux}
      fi
      
      if [ $Action -eq 4 ];then
              echo ${string//Hadoop/Linux}
      fi
      

      3.习题3:查看内存/当前使用状态,如果使用率超过80%则报警发邮件

      思路: 
      	1.如何查看内存整体情况  free -m
      	2.如何查看内存的百分比  free -m | awk '/^Mem/ {print $3/$2*100}'
      	3.设定的阈值与已使用量进行比对   80 是大于 已使用,还是小于已使用
      			大于 则报警
      			小于 则不管
      
      [root@web01 ~]# cat check_memory.sh
      #!/bin/bash
      ##############################################################
      # File Name: check_memory.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      Mem_Use=$(free -m | awk '/^Mem/ {print $3/$2*100}')
      
      if [ ${Mem_Use%.*} -ge 80 ];then
              echo "内存已经超过所设定的阈值,请尽快处理,当前已使用内存为 ${Mem_Use} "
          else
              echo "内存当前状态良好,当前已使用内存为 ${Mem_Use%.*}%"
      fi
      
  • 6.变量的运算

    • 1.什么是变量运算? 小学学习的 + - x /
    • 2.为什么要学习呢?
    • 3.shell使用什么方式来实现变量的运算呢?
      • 1.expr
      • 2.$(())
      • 3.$[]
      • 4.bc、awk 小数运算
      • % 余数如果为0,说明两者之间整除

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IODkYQ4C-1594120060832)(Shell编程实践.assets/image-20200603152445242.png)]

[root@web01 ~]# num1=10
[root@web01 ~]# num2=20
[root@web01 ~]#
[root@web01 ~]# expr $num1 + $num2
30
[root@web01 ~]#
[root@web01 ~]# echo $(( $num1 + $num2 ))
30
[root@web01 ~]# echo $[ $num1 + $num2 ]
30
[root@web01 ~]# echo $[ $num1 - $num2 ]
-10
[root@web01 ~]# echo $[ $num1 * $num2 ]
200
[root@web01 ~]# echo $[ $num1 / $num2 ]
0
  • 1.根据系统的时间,打印今年和明年时间。

  • 2020
    2021
    打印时间使用 date命令   date +%Y
    
    [root@web01 ~]# echo "This is $(date +%Y) year"
    This is 2020 year
    [root@web01 ~]# echo "This is $(( $(date +%Y) +1 )) year"
    This is 2021 year
    
  • 2.根据系统时间获取今年还剩下多少个星期,已经过了多少个星期。

  • 1.获取今年是一年中的第多少天? date +%j
    2.通过获取已过的天数,/7 就能得到已经过了多少周了。
    3.通过(365 - 100)/7 还剩下多少周。
    
    [root@web01 ~]# cat vars-2.sh
    #!/bin/bash
    ##############################################################
    # File Name: vars-2.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    echo "今年已经过了 $(date +%j) days"
    echo "记你已经过了 $(( $(date +%j) /7 ))  weeks"
    echo "距离新年还剩多少周 $(( ( 365 - $(date +%j) )  /7 ))  weeks"
    
  • 3.完成一个 “简单” 的计算机功能,通过read方式传入2个值【而不是传参的方式】,进行 加、减、乘、除:

1.read传递两个值
2.将传递的两个值,分别使用两个变量进行接收
3.对两个变量进行加减乘除。

[root@web01 ~]# cat vars-3.sh
#!/bin/bash
##############################################################
# File Name: vars-3.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

read -p "请输入要计算的第一个数字: " num1
read -p "请输入要计算的第二个数字: " num2

echo "$num1 + $num2 = $(( $num1 + $num2 ))"
echo "$num1 - $num2 = $(( $num1 - $num2 ))"
echo "$num1 * $num2 = $(( $num1 * $num2 ))"
echo "$num1 / $num2 = $(( $num1 / $num2 ))"

1.介绍if

  • 1.什么是if
    • 判断,if是模仿人类的判断来进行的,true、false两种结果。

2.if基础语法

  • 单条件

  • # 伪代码
    if [ 如果你有房 ];then
    		那么我就嫁给你
    fi
    
    if [ $1 -eq $2 ];then		#如果$1等于$2 那么输出ok
    	echo "ok"
    fi
    
  • 双条件

  • #伪代码
    
    if [ 如果你有房 ];then
    		那么就嫁			#true 真	条件成立
    else
    		再见				#false 假 条件不成立
    fi
    
    if [ $1 -eq $2 ];then		
    		echo "ok"				#如果$1等于$2 那么输出ok
    else
    		echo "Error"		#如果$1不等于$2 那么输出error
    fi
    
  • 多条件

  • #伪代码
    if [ 如果你有房 ];then
    		就嫁
    elif [ 如果你有车 ];then
    		就嫁
    elif [ 如果有钱 ];then
    		就嫁
    else
    		GG
    fi
    
  • 1.单分支,判断当前用户是不是root执行,如果不是那么返回“ERROR”

  • [root@web01 shell-if]# cat if-03.sh
    #!/bin/bash
    ##############################################################
    # File Name: if-03.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    if [ $USER != "root" ];then
        echo "ERROR!"
        exit
    fi
    
  • 2.双分支,判断当前登录用户是管理员还是普通用户,如果是管理员输出”hey admin“ 如果是普通用户输出”hey guest“

  • [root@web01 shell-if]# cat if-04.sh
    #!/bin/bash
    ##############################################################
    # File Name: if-04.sh
    # Author:wenjie
    # Organization: [email protected]
    ##############################################################
    
    if [ $USER == "root" ];then
        echo "hey admin"
    else
        echo "hey guest"
    fi
    
  • 3.多分支,根据输入一个用户名称,判断输入的用户是否存在当前系统,如不存在则再次判断用户是否在/home下拥有家目录,如果都没有则提示不存在。

  • 1.read 提示用户交互,然后输入一个用户名称,这个输入的用户名称需要存储到一个变量中。
    2.grep 过滤/etc/passwd 中是否存在这个用户
    3.判断/home下是否有该用户的家目录
    4.else,提示用户不存在。
    
    [root@web01 shell-if]# cat if-05.sh
    #!/bin/bash
    ##############################################################
    # File Name: if-05.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    read -p "请输入你要查询的用户: " users
    
    if grep "$users" /etc/passwd &>/dev/null;then
        echo "$users 存在系统中"
    
    elif ls -d /home/$users &>/dev/null; then
        echo "$users 用户不存在该系统,但用户家目录存在"
    
    else
        echo "$users 不存在该系统中,也不存在家目录"
    fi
    
  • 4.通过脚本传入两个参数,进行整数关系比较。比如: if.sh [ 1 2 | 2 2 | 2 3 ],请使用双分支和多分支两种方式实现。

  • [root@web01 shell-if]# cat if-06.sh
    #!/bin/bash
    ##############################################################
    # File Name: if-06.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    if [ $1 -eq $2 ];then           #判断$1与$2是否相等
        echo "$1 = $2"
    else
        if [ $1 -gt $2 ];then       #判断$1 是否大于 $2
                echo "$1 > $2"
            else                    # $1 小于 $2
                echo "$1 < $2"
        fi
    fi
    
    
    
    # 多分支
    [root@web01 shell-if]# cat if-07.sh
    #!/bin/bash
    ##############################################################
    # File Name: if-06.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    if [ $1 -eq $2 ];then       #判断$1与$2是否相等
        echo "$1 = $2"
    elif [ $1 -gt $2 ];then     #判断$1 是否大于 $2
        echo "$1 > $2"
    else                        #$1 小于 $2
         echo "$1 < $2"
    fi
    

3.基于文件进行判断

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9zHMLEUz-1594120060833)(Shell编程实践.assets/image-20200604100119611.png)]

    • 1.备份文件至/backup/system/filename-2020-06-04,如果该目录不存在则自动创建。

    • 1.需要用户交互的输入需要备份的文件
      2.判断目录是否存在。如果不存在则创建
      3.执行cp命令完成备份操作。
      
      [root@web01 shell-if]# cat if-08.sh
      #!/bin/bash
      ##############################################################
      # File Name: if-08.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      Dest=/backup/system
      Date=$(date +%F)
      
      read -p "请输入你要备份的文件: " Src_File
      
      #判断目录是否存在,如果目录不存在则创建该目录
      if [ ! -d $Dest ];then
          mkdir -p $Dest
      fi
      
      # 执行备份操作
      cp -rp ${Src_File} $Dest/filename_${Date}
      
    • 2.继需求1,判断备份的文件是否存在,如果不存在则提示”No such file or directory“,然后退出。

    • [root@web01 shell-if]# cat if-08.sh
      #!/bin/bash
      ##############################################################
      # File Name: if-08.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      Dest=/backup/system
      Date=$(date +%F)
      
      read -p "请输入你要备份的文件: " Src_File
      
      #判断用户输入的文件是否存在
      if [ ! -f ${Src_File} ];then
          echo "${Src_File} No such file or directory"
          exit
      fi
      
      #判断目录是否存在,如果目录不存在则创建该目录
      if [ ! -d $Dest ];then
          mkdir -p $Dest
      fi
      
      # 执行备份操作
      cp -rp ${Src_File} $Dest/filename_${Date}
      
    • 3.继需求1、2,判断备份的文件是否为空,如果为空则提示"This is file empty",然后退出。

    • [root@web01 shell-if]# cat if-08.sh
      #!/bin/bash
      ##############################################################
      # File Name: if-08.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      Dest=/backup/system
      Date=$(date +%F)
      
      read -p "请输入你要备份的文件: " Src_File
      
      #判断用户输入的文件是否存在
      if [ ! -f ${Src_File} ];then
          echo "${Src_File} No such file or directory"
          exit
      fi
      
      #判断用户备份的文件是否为空
      if [ ! -s ${Src_File} ];then
          echo "${Src_File} This is file empty"
          exit
      fi
      
      #判断目录是否存在,如果目录不存在则创建该目录
      if [ ! -d $Dest ];then
          mkdir -p $Dest
      fi
      
      # 执行备份操作
      cp -rp ${Src_File} $Dest/filename_${Date}
      

4.基于整数进行判断

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vSwN4xZH-1594120060836)(Shell编程实践.assets/image-20200604103159665.png)]

  • 1.用户执行脚本,sh status.sh nginx,则检查nginx服务的运行状态。(仅支持传递一个参数)

  • 1.控制用户仅能传递一个参数  $#
    2.检查服务的运行状态,systemctl status nginx
    
    
    [root@web01 shell-if]# cat if-09.sh
    #!/bin/bash
    ##############################################################
    # File Name: if-09.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    if [ $# -eq 1 ];then
        #检查服务的状态
        systemctl status $1 &>/dev/null
        #判断服务运行的结果
        if [ $? -eq 0 ];then
            echo "$1 服务正在运行"
        else
            echo "$1 服务没有运行"
        fi
    else
        echo "USAGE: sh $0 service_name"
        exit
    fi
    
  • 2.查看磁盘/当前使用状态,如果使用率超过30%则报警发邮件

  • 1.如何查看 /分区的磁盘使用状态
    2.提取 /分区使用状态百分比
    3.将已使用的百分比与我们设定的阈值30%进行比对
    	超过百分之30则发邮件报警 ( 写到一个文件中 用户:时间:磁盘的状态情况 )
    	没有超过百分之30则不处理
    
    [root@web01 shell-if]# cat if-10.sh
    #!/bin/bash
    ##############################################################
    # File Name: if-10.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    #1.提取磁盘使用的百分比
    Disk_Use=$(df -h  | grep '/$' |awk '{print $5}')
    Date=$(date +%F-%T)
    
    #2.判断磁盘使用百分比是否超过30,如果超过,则写入一个文件中。
    if [ ${Disk_Use%\%} -ge 30 ];then
            echo "${USER}:${Date}: Disk Is Use ${Disk_Use}" >> /tmp/disk_use.txt
    fi
    

5.基于字符进行判断

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-41ttBzsA-1594120060838)(Shell编程实践.assets/image-20200604110921951.png)]

    [root@web01 shell-if]# cat if-11.sh
    #!/bin/bash
    ##############################################################
    # File Name: if-11.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
   read -p "请输入一个字符: " action
  
    if [ -z $action ];then
        echo "请不要直接回车..."
        exit
    fi
    
    echo "你输入的是: $action"
  • 额外补充一个:多条件比对
    if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
        umask 002
    else
        umask 022
    fi
    
    if [ $UID -gt 199 -a "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
        umask 002			#真  (必须两个条件都为真)
    else
        umask 022			#假	(只要有一个条件不为真)
    fi
    
    真真为真
    真假为假
    
**提示学生输入自己的成绩。
1.如果分数大于0小于59提示补考。
2.如果分数大于60小于70提示良好。
3.如果分数大于71小于85提示好。
4.如果分数大于86小于100提示优秀。*

```bash
[root@web01 shell-if]# cat if-12.sh
#!/bin/bash
##############################################################
# File Name: if-12.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

read -p "请输入你的成绩: " Cj

if [ -z $Cj ];then
    echo "请输入正确的成绩分数.."
    exit
fi

if [ $Cj -ge 0 ] && [ $Cj -le 59 ];then
    echo "你需要补考"
elif [ $Cj -ge 60 ] && [ $Cj -le 70 ];then
    echo "成绩良好"
elif [ $Cj -ge 71 ] && [ $Cj -le 85 ];then
    echo "成绩挺好"
elif [ $Cj -ge 86 ] && [ $Cj -le 100 ];then
    echo "成绩优秀"
else
    echo "成绩的分数范围是0-100"
    exit
fi

#注意,该脚本存在一个缺陷:如果输入非数字,则会出现语法错误。 (问题:怎么才能让别人输入的必须是数字呢?)
```
#控制用户输入的是纯数字

if [[ ! $Cj =~ ^[0-9]+$ ]];then
    echo "请输入纯数字,,"
    exit
fi

编写一个创建用户的脚本。 (wenjie10)
1.提示用户输入要创建用户的前缀,必须是英文。 wenjie
2.提示用户输入后缀,必须是数字。 10
3.如果前缀和后缀都没有问题,则进行用户创建。【如果该用户已经创建,需要提示已创建,没有创建才进行创建操作。】

1.交互:read
2.判断用户输入的前缀是否是全英文
3.判断用户输入的后缀是否是全数字
4.判断  前缀+后缀  是否存在系统中
	存在: 提示该用户已存在系统中
	否则: 创建该用户
	

[root@web01 shell-if]# cat if-13.sh
#!/bin/bash
##############################################################
# File Name: if-13.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

read -p "请输入你要在该系统中创建的用户前缀[英文] " qz
if [[ ! $qz =~ ^[a-Z]+$ ]];then
    echo ""
    echo "------------------------------"
    echo "用户的前缀需要输入纯英文...."
    exit
fi

read -p "请输入你要在该系统中创建的用户后缀[数字] " hz
if [[ ! $hz =~ ^[0-9]+$ ]];then
    echo ""
    echo "------------------------------"
    echo "用户的后缀需要输入纯数字..."
    exit
fi

users=${qz}${hz}

id $users &>/dev/null		#0表示用户存在系统   1表示用户不存在系统
if [ $? -ne 0 ];then
    useradd $users
    echo "$users 创建成功"
else
    echo "$users 已经存在"
fi

6.shell-if练习题

需求1:判断一个机器是否存活,能ping通就算存活。
	1.是传递一个IP去 探测
			1.read 交互传递
			2.直接脚本后面跟上IP地址  ( 传参 )
	
[root@web01 shell-if]# cat  if-14.sh
#!/bin/bash
##############################################################
# File Name: if-14.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

if [ $# -ne 1 ];then
    echo "请传递一个IP地址"
    exit
fi

ping -c2 $1 &>/dev/null
if [ $? -eq 0 ];then
    echo -e "\033[32m $1 地址通 \033[0m"
else
    echo -e "\033[31m $1 地址不通  \033[0m"
fi
	
	
	2.准备一个ip.txt文件  ( 很多的IP地址 )  ( "了解" --后面讲解的内容  for[root@web01 shell-if]# cat if-15.sh
#!/bin/bash
##############################################################
# File Name: if-14.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

for ip in $(cat ip.txt)												#每次获取一行内容复制给ip变量
do
    ping -c2 $ip &>/dev/null
    if [ $? -eq 0 ];then
        echo -e "\033[32m $ip 地址通 \033[0m"
    else
        echo -e "\033[31m $ip 地址不通  \033[0m"
    fi
done


需求2:监控内存小于500M和磁盘容量小于10G,则发邮件报警
	1.提取内存还剩多少可用					free -m | awk '/^Mem/ {print $NF}'
	2.提取磁盘/ 容量,还剩多少可用		df -h | awk '/\/$/ {print $4}'
	3.if 并且关系    
	
[root@web01 shell-if]# cat if-16.sh
#!/bin/bash
##############################################################
# File Name: if-16.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

Free=$(free -m | awk '/^Mem/ {print $NF}')
Disk=$(df -h | awk '/\/$/ {print $4}')

if [ $Free -lt 500 -a ${Disk%G} -lt 10 ];then			#内存低于500M并且磁盘/分区可用不足10G 
        echo "报警"
    else
        echo "当前状态良好"
        echo "内存可用大小为: ${Free}M 磁盘可用空间是: ${Disk}"
fi
	
需求3:检测本机当前用户是否为管理员,如果是则使用 yum 安装 vsftpd 如果不是,则提示您非管理员。

	1.如何判断自己是不是管理员root
			$USER  = root
			$UID   = 0
			
[root@web01 shell-if]# cat if-17.sh
#!/bin/bash
##############################################################
# File Name: if-17.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

#if [ $USER == "root" ];then         #这种方式不够严谨(因为不是每台 机器的root都是超级管理员)
if [ $UID -eq 0 ];then             #这种方式较为严谨(UID为0一定是超级管理员)
    yum install vsftpd -y
    if  [ $? -eq 0 ];then
        echo -e "\033[32m vsftpd服务已经安装完毕 \033[0m"
    else
        echo "vsftpd服务在安装过程中出现意外"
    fi
else
    echo "你不是管理员用户,没有权限执行"
fi


需求4:根据相同的系统不同版本,配置不同的yum源
	centos
		6			6系统配置6的源
		7			7系统配置7的源
	保证脚本的通用,在6或7系统执行时,不需要修改脚本。

	1.首先判断当前系统是什么版本。
	2.根据不同的版本配置不同源即可。

[root@web01 shell-if]# cat if-18.sh
#!/bin/bash
##############################################################
# File Name: if-18.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

system_status=$(cat /etc/redhat-release | awk '{print $(NF-1)}')
if [ ${system_status%%.*} -eq 7 ];then
    echo "执行安装centos7的源"

elif [ ${system_status%%.*} -eq 6 ];then
    echo "执行安装centos6的源"
else
    echo "没有识别出操作系统版本"
    exit
fi
	
		
需求5:安装不同版本的PHP,使用echo输出即可,不用真的安装。
	1.你得给我提供几个可以安装的版本把?
	2.还需要交互输入我的选择:
	3.程序根据用户的选择来进行判断,进而安装不同的php版本。
	
[root@web01 shell-if]# cat if-19.sh
#!/bin/bash
##############################################################
# File Name: if-19.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

cat <<EOF
##############################
1) Install PHP 5.1
2) Install PHP 5.5
3) Install PHP 7.1
4) Install PHP 7.2
##############################
EOF
read -p "请输入你需要安装的php版本 [ 1 | 2 | 3 | 4 ]: " number

if [[ ! $number =~ ^[0-9]+$ ]];then
    echo "请填写对应的序号,不要随意填写"
    exit
fi

if [ $number -eq 1 ];then
    sleep 3
    echo -e "\033[32m Install php5.1 Is Done...... \033[0m"
elif [ $number -eq 2 ];then
    echo "Install php5.5 Is Done......"
elif [ $number -eq 3 ];then
    echo "Install php7.1 Is Done......"
elif [ $number -eq 4 ];then
    echo "Install php7.2 Is Done......"
fi

需求6:
1.如果姑娘小于18岁,打印“未成年” 
2.如果姑娘大于18岁小于25岁,打印“表白”
3.如果姑娘大于25岁小于45岁,打印“阿姨好”。
4.如果姑娘大于45岁,打印“奶奶好”

需求7:写一个脚本,提示用户输入身高,如果身高达到180以上全票,120以下免票,其余不能进。
	1.需要交互
	2.判断超过180则提示全票
	3.判断低于120 则免票
	4.其余全部 提示拒绝。

[root@web01 shell-if]# cat if-20.sh
#!/bin/bash
##############################################################
# File Name: if-20.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

read -p "请输入你的身高: " Action
if [[ ! $Action =~ ^[0-9]+$ ]];then
    echo "请输入纯整数"
    exit
fi

##############################
if [ $Action -ge 180 ];then					#大于180
    echo "你需要购买全票"
else
    if [ $Action -lt 120 ];then			#低于120
        echo "你可以免票通过"
    else
        echo "不好意思,你不能进"			#既不大于180 也不低于120 
        exit
    fi
fi

需求8:使用root用户清空/var/log/messages日志,并每次执行保留最近100行
	1.必须是root
	2.备份一下文件 message 最后100行 message.bak
	3.将message.bak > message
	4.删除message.bak
	
	
	[root@web01 shell-if]# cat  if-21.sh
#!/bin/bash
##############################################################
# File Name: if-21.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

Log_Path=/var/log/messages
#必须是超级管理员
if [ $UID -ne 0 ];then
    echo "Permission Denied..."
    exit
fi

if [ -f $Log_Path ];then
    #提取文件的最后100行
    tail -100 $Log_Path > ${Log_Path}.bak

    #清空message文件,并重定向之前最后100行内容
    cat ${Log_Path}.bak > $Log_Path

    #删除.bak文件
    rm  -f  ${Log_Path}.bak
    echo "Clean Log Done......."

else
    echo "$Log_Path No such file or directory"
    exit
fi
	

需求9:判断nginx服务是否正常启动,可以通过systemctl、ps、netstat、curl多种方式。
	systemctl
	1.systemctl status nginx
	2.查看状态返回结果   3 表示没启动   0 表示启动

[root@web01 shell-if]# cat if-22.sh
#!/bin/bash
##############################################################
# File Name: if-22.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

systemctl status nginx &>/dev/null

if  [ $?  -eq 0 ];then
    echo "Nginx 正在运行中...."
else
    systemctl restart nginx &>/dev/null
    if [ $? -eq 0 ];then
        echo "nginx重启启动成功..."
    else
        echo "nginx重启启动失败..."
    fi
fi


需求10:写一个Nginx安装脚本,加入判断,当上一步执行成功在执行下一步,否则退出脚本
1.检查网络
2.检查 yum源  (省略)
3.yum安装软件
...........
4.启动nginx

[root@web01 shell-if]# cat if-23.sh
#!/bin/bash
##############################################################
# File Name: if-23.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

#1.测试网络
ping -c2 www.baidu.com &>/dev/null
if [ $? -ne 0 ];then
    echo "网络故障..."
    exit
fi

#2.执行yum操作
rpm -q nginx &>/dev/null
rc=$?

if [ $rc -eq 0 ];then
        echo "nginx已经存在系统"
    else
        yum install nginx -y
fi



需求11:在每月第一天备份并压缩/etc目录的所有内容,存放到/opt/bak目录,存放的形式2019_04_10_etc.tar.gz,脚本名称为fileback,存放在/root的家目录下。
	1.定时任务  (每月第一天)
	2.备份的源 /etc/ 需要打包压缩命名为2019_04_10_etc.tar.gz
	3.存储的 路径  /opt/bak

[root@web01 shell-if]# cat if-24.sh
#!/bin/bash
##############################################################
# File Name: if-24.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

Src=/etc
Dest=/opt/bak
Date=$(date +%F)

#1.确定存储的目录存在
if [ ! -d $Dest ];then
    mkdir -p $Dest
fi

#2.打包/etc直接存储至  $Dest目录中
cd /  && \
tar czf $Dest/${Date}_etc.tar.gz etc/

#3.检查一下
if [ ! -f $Dest/${Date}_etc.tar.gz ];then
    echo "备份失败......."
fi


需求12:输入三个数并进行升序排序
	1.控制传递的参数是3个
	2.对传递的参数进行升降排序
	
[root@web01 shell-if]# cat if-25.sh
#!/bin/bash
##############################################################
# File Name: if-25.sh
# Author: wenjie
# Organization: [email protected]
##############################################################
if [ $# -ne 3 ];then
    echo "必须传递三个参数"
    exit
fi

echo "$1 $2 $3" | xargs -n1 | sort -n	
	

需求13:提示用户输入年份后判断该年是否为闰年 能整除4, 并且不能被100整除则为 闰年

	1.提示用户输入年份,read交互操作:  ( 闰年、平年 )
	2.闰年计算公式:
				1.公式1: 年份 / 4 = 整数 并且 年份 / 100 = 余数
				2.公式2: 年份 /400 =整除就是闰年
				
[root@web01 shell-if]# cat if-26.sh
#!/bin/bash
##############################################################
# File Name: if-26.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

read -p "请输入你想查询的年份: " Action

if [ $(($Action%4)) -eq 0  -a $(($Action%100)) -ne 0 ] || [ $(($Action%400)) -eq 0 ];then
    echo "$Action 是闰年"
else
    echo "$Action 是平年"
fi

需求14:根据用户输入密码位数,生成随机密码(包含数字、大小写字母、特殊符号)
  1.怎么生成随机数 mkpasswd -l 8
  2.控制输入的长度,最少8位
  
[root@web01 shell-if]# cat if-27.sh
#!/bin/bash
##############################################################
# File Name: if-27.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

read -p "请输入你要生成的随机密码位数: " Action

#让用户必须输入数字
if [[ ! $Action =~ ^[0-9]+$ ]];then
    echo "请输入整数,,,,"
    exit
fi

#判断用户需要生成的字符长度必须高于7
if [ $Action -ge 7 ];then
    pw=$(mkpasswd -l $Action)
    echo "你生成的随机密码是 $Action 位,密码如下: $pw"
else
    echo "随机的密码的复杂度必须满足7位以上"
    exit
fi

备份mysql,手动输入你需要备份的库名称,以备份wordpress为例: mysqldump -uroot -pwenjie.com -B wordpress > /opt/word.sql

1.给用户看一下目前有哪些数据库

2.提示用户输入 他需要备份 的 数据库名称

3.判断保存的目录是否存在

3.执行备份命令

[root@db01 ~]# cat backup_mysql.sh
#!/usr/bin/bash

Path=/backup/mysql
Date=$(date +%F)

#判断备份的目录是否存在,如果不存在则执行创建操作 ( || 前者命令执行成功,后者命令不执行。前者命令执行不成功,后者命令执行。)
[ -d $Path ] || mkdir -p $Path

mysql -uroot -pwenjie.com -e "show databases;"			#非交互式展示所有的库
read -p "请输入你要备份的库名称: " dbname

# 如果 dbname变量 为空则执行else下面的内容,如果  dbname 不为空这执行then下面的语句。
if [ ! -z $dbname ];then
	mysqldump -uroot -pwenjie.com -B $dbname > $Path/${dbname}-${Date}.sql
else
	echo "请输入正确的库名称..."
	exit
fi

增加判断:如果用户填写的库名称不存在,则不让其进行备份操作。

[root@db01 ~]# cat backup_mysql.sh
#!/usr/bin/bash

Path=/backup/mysql
Date=$(date +%F)
[ -d $Path ] || mkdir -p $Path

mysql -uroot -pwenjie.com -e "show databases;"
read -p "请输入你要备份的库名称: " dbname

if [ ! -z $dbname ];then
	database_name=$(mysql -uroot -pwenjie.com -e "show databases;" | grep -w "$dbname" | wc -l)
	if [ $database_name -eq 1 ];then
		mysqldump -uroot -pwenjie.com -B $dbname > $Path/${dbname}-${Date}.sql
	else
		echo "你输入 $dbname 库名称不对,请重新选择并输入"
		exit
	fi

else
	echo "请输入正确的库名称..."
	exit
fi
  • 1.什么是 case
  • 2.case使用场景
  • 3.case执行流程
  • 4.case基础语法、脚本练习

4.1 Case基本介绍

  • 1.什么是case

    • case和 if 多分支条件判断 语句差不多,或者说 是一样的,只不过case要比 if 要更加的规范,更加的方便。
  • 2.case使用场景

    • case需要实现定义好规则,然后根据用户传入 的参数,进行匹配,加载不同的匹配规则内容。
    • 比如: nginx启停脚本。 ( 启动 | 停止 | 重启 等等操作 )
    • 1.写好 启动、停止、重启等三个预案,然后根据用户的 选择匹配对应的预案进行执行即可。
  • 3.case的执行流程

    • 进行挨个匹配,匹配成功则直接执行,后续的预案就不在进行匹配了 。
    • 如果所有的都没有匹配成功,那么自动进行一个 接收所有的预案中。 *)
  • 4.case基础语法

    • case $1 in     #  可以是 $1 也可以是 变量
      
      	start) 
      				command
      				;;
      	stop)
      			command
      			;;
      	restart)
      			command
      			;;
      	*)
      		command
      esac
      
    • 演示一个例子,来对比一下 if 和 case

    • [root@web01 shell-case]# cat case-1.sh
      #!/bin/bash
      ##############################################################
      # File Name: case-1.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      #!/bin/bash
      cat <<eof
      ****************
      ** 1. backup  **
      ** 2. copy    **
      ** 3. quit    **
      ****************
      eof
      
      read -p "请输入你想执行的操作: " OP
      
      if [ $OP -eq 1 ];then
          echo "Backup Is Done..."
      elif [ $OP -eq 2 ];then
          echo "Copy Is Done...."
      
      elif [ $OP -eq 3 ];then
          exit
      fi
      
      #####
      [root@web01 shell-case]# cat case-2.sh
      #!/bin/bash
      ##############################################################
      # File Name: case-1.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      #!/bin/bash
      cat <<eof
      ****************
      ** 1. backup  **
      ** 2. copy    **
      ** 3. quit    **
      ****************
      eof
      
      read -p "请输入你想执行的操作: " OP
      
      case $OP in
          1|backup|b|back)
              echo "Backup Is Done..."
              ;;
          2)
              echo "Copy IS Done...."
              ;;
          3)
              exit
              ;;
          *)
              echo "USAGE: sh $0 [ 1 | 2 | 3 ]"
              exit
      esac
      

4.2 Case Job

  • 1.使用case实现nginx服务启停脚本。

  • 1.预案
    	启动
    		1.是否已经启动过了,
    				如果启动过了则提示已经启动成功。
    				如果没有启动,则启动服务即可。
    	停止
    		1.判断nginx是否是已启动状态。
    				如果是启动,那我们可以尝试  nginx -s stop  停止
    				如果没有启动,那么则提示 nginx服务未启动。
    	重启
    			1.先停止,后启动。
    			
    			
    			systemctl
    			ps  通过进程方式来实现启停     ( nginx 、 rsync[root@web01 shell-case]# cat case-3.sh
    #!/bin/bash
    ##############################################################
    # File Name: case-3.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    . /etc/init.d/functions
    
    # start | stop | restart |
    case $1 in
        start)
            #1.判断是否已启动过
            ngx_status=$(systemctl status nginx   | grep Active | awk  '{print $2}')
    
            #2.进行字符串的比较(不是整数比较、也不是正则比较、也不是文件比较)
            if [ "$ngx_status" == "inactive" ];then
                systemctl start nginx
                action  "Nginx启动成功..." /bin/true
            elif [ "$ngx_status" == "active" ];then
                action  "Nginx启动成功..." /bin/true
                exit
            fi
            ;;
            
        stop)
                ngx_status=$(systemctl status nginx   | grep Active | awk  '{print $2}')
                if [ "$ngx_status" == "inactive" ];then
                    action "Nginx停止成功..."  /bin/true
                elif  [ "$ngx_status" == "active" ];then
                    systemctl stop nginx
                    action "Nginx停止成功..." /bin/true
                fi
            ;;
        *)
            echo "USAGE: sh $0 [ start | stop | restart ] "
    esac
    
    
    #### nginx没有启停的脚本方式:
    	启动: nginx
    	停止: nginx -s stop
    	重启:
    				nginx -s stop
    				nginx
    
    
    [root@web01 shell-case]# cat case-4.sh
    #!/bin/bash
    ##############################################################
    # File Name: case-4.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    .  /etc/init.d/functions
    
    case $1 in
        start)
            #判断nginx是否启动
            ngx_status=$(ps  -ef |grep nginx | grep -v grep   | wc -l)
            if [ $ngx_status -ge 2 ];then					#如果大于2则提示 nginx是 启动状态
                action "Nginx正在运行" /bin/false
            else																#否则执行启动 nginx命令
                /usr/sbin/nginx &>/dev/null
                if [ $? -eq 0 ];then						#判断nginx启动 成功还是失败
                    action "Nginx启动成功" /bin/true
                else
                    action "Nginx启动失败" /bin/false
                fi
            fi
                ;;
        stop)
                ngx_status=$(ps  -ef |grep nginx | grep -v grep   | wc -l)
                if [ $ngx_status -eq 0 ];then
                    action "Nginx已经停止" /bin/false
                else
                    /usr/sbin/nginx -s stop &>/dev/null
                    if  [ $? -eq 0 ];then
                        action "Nginx停止成功" /bin/true
                    else
                        action "Nginx停止失败"  /bin/false
                    fi
                fi
                ;;
        restart)
                ngx_status=$(ps  -ef |grep nginx | grep -v grep | wc -l)
                if  [ $ngx_status -eq 0 ];then						#如果 过滤的进程 为0 说明nginx 没启动
                    action "Nginx已是停止状态" /bin/false
                    /usr/sbin/nginx  &>/dev/null					#既然 没有启动,那么就 尝试启动 nginx
                    if [ $? -eq 0 ];then									#判断启动nginx是成功还是失败
                        action "Nginx重启成功" /bin/true
                    else
                        action "Nginx重启失败" /bin/false
                    fi
                else																			#如果 过滤的进程 不是 0 说明nginx 已经是启动状态
                    /usr/sbin/nginx -s stop &>/dev/null		#执行停止nginx操作
                    if [ $? -eq 0 ];then									#判断停止是否成功
                        action "Nginx停止成功" /bin/true	 #如果$?为0说明停止成功
                        /usr/sbin/nginx &>/dev/null				#然后紧接着尝试启动nginx
                        if  [ $? -eq 0 ];then
                            action "Nginx启动成功" /bin/true
                        else
                            action "Nginx启动失败" /bin/true
                        fi
                    else																#如果停止nginx失败了,那么就提示停止失败
                        action "Nginx停止失败" /bin/false
                    fi
                fi
                ;;
            *)
                echo "USAGE: sh $0 [  start | stop | restart ]"
        esac
        
        
        # curl 命令判断
    
  • 2.使用case实现nginx状态监控脚本。7种

  • 1.先得将7种状态展示出来。
    2.将每种状态分别 提取。
    [root@web01 shell-case]# curl -HHost:nginx.wenjie.com http://127.0.0.1:80/nginx_status
    
    
    [root@web01 shell-case]# cat  case-5.sh
    #!/bin/bash
    ##############################################################
    # File Name: case-5.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    #建议:
    # 先进行curl 获取状态,然后将 状态存储至某一个目录下
    # 然后在通过awk对文件进行取值
    # 很多地方其实可以使用变量来替代  域名  端口
    
    case $1 in
        Active|active)
            curl -s -HHost:nginx.wenjie.com http://127.0.0.1:80/nginx_status | awk '/Active/ {print $NF}'
            ;;
        accept)
            curl -s -HHost:nginx.wenjie.com http://127.0.0.1:80/nginx_status |awk 'NR==3 {print $1}'
            ;;
        handled)
            curl -s -HHost:nginx.wenjie.com http://127.0.0.1:80/nginx_status |awk 'NR==3 {print $2}'
             ;;
        requests)
            curl -s -HHost:nginx.wenjie.com http://127.0.0.1:80/nginx_status |awk 'NR==3 {print $3}'
            ;;
        reading)
            curl -s -HHost:nginx.wenjie.com http://127.0.0.1:80/nginx_status |awk 'NR==4 {print $2}'
            ;;
        writing)
            curl -s -HHost:nginx.wenjie.com http://127.0.0.1:80/nginx_status |awk 'NR==4 {print $4}'
            ;;
        waiting)
            curl -s -HHost:nginx.wenjie.com http://127.0.0.1:80/nginx_status |awk 'NR==4 {print $NF}'
            ;;
        *)
            echo "USAGE: sh $0 [ active | accept | handled | requests | reading | writing | waiting ]"
    esac
    
  • 3.使用case实现php-fpm状态监控脚本。

  • 1.配置 php-fpm 状态页面。
    2.取值 ( 需要大家先curl一下 存储到文件中,然后再awk处理。)
    
    
    1.配置php-fpm,开启状态模块。
    [root@web01 shell-case]# vim /etc/php-fpm.d/www.conf
    pm.status_path = /phpfpm_status			#增加一行,开启php-fpm的 状态页面( 访问的路径 ) 
    
    2.配置nginx
    [root@web01 shell-case]# cat /etc/nginx/conf.d/nginx.wenjie.com.conf
    server {
        listen 80;
        server_name nginx.wenjie.com;
    
        location = /nginx_status {
            stub_status;
        }
    
        location /phpfpm_status {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }
    
    3.重启服务
    [root@web01 shell-case]# systemctl restart nginx php-fpm
    
    
    4.访问测试:(用于内部监控,所以无需其他人访问,只需要本地127地址可以访问到就可以了)
    [root@web01 shell-case]# curl -s  -HHost:nginx.wenjie.com http://127.0.0.1/phpfpm_status
    pool:                 www
    process manager:      dynamic
    start time:           05/Jun/2020:14:14:58 +0800
    start since:          45
    
    accepted conn:        9		#当前接收的连接数
    listen queue:         0		#请求的队列,如果这个值不为0,那么你可能需要增加php的进程数	(队列长度持续多长时间达到200)
    max listen queue:     0		#最大的请求队列长度。
    listen queue len:     128	#
    idle processes:       4		#空闲的进程数
    active processes:     1		#活跃的进程数
    total processes:      5		#总的进程数
    max active processes: 1		#最大的活跃进程数是 1
    max children reached: 0		#超过最大进程数的峰值次数,如果不为0,需要调整php-fpm的进程数	( 超过5次以上就要触发报警 )
    
    
    Domain_Host=nginx.wenjie.com
    
    case $1 in
    	idle_process)
    		curl -s  -HHost:"${Domain_Host}" http://127.0.0.1/phpfpm_status | awk '/idle processes/ {print $NF}'
    		;;
    	active_process)
    		curl -s  -HHost:"${Domain_Host}" http://127.0.0.1/phpfpm_status | awk '/^active processes/  {print $NF}'
    		;;
    	total_process)
    		curl -s  -HHost:"${Domain_Host}" http://127.0.0.1/phpfpm_status | awk '/^total processes/ {print $NF}'
    		;;
    	max_active_process)
    		curl -s  -HHost:"${Domain_Host}" http://127.0.0.1/phpfpm_status | awk '/^max active processes/  {print $NF}'
    		;;
    	accepted_conn)
    		curl -s  -HHost:"${Domain_Host}" http://127.0.0.1/phpfpm_status | awk '/^accepted conn/  {print $NF}'
    		;;
    	listen_queue)
    		curl -s  -HHost:"${Domain_Host}" http://127.0.0.1/phpfpm_status | awk '/^listen queue:/ {print $NF}'
    		;;
    		*)
    			echo "USAGE sh $0 [ idle_process | active_process | total_process | max_active_process | accepted_conn | listen_queue ]"
    esac
    
  • 5.case写一个rsync服务启停脚本。

    • 启动 rsync --daemon
    • 停止 pkill rsync
    • 重启
[root@web01 shell-case]# cat  case-8.sh
#!/bin/bash
##############################################################
# File Name: case-8.sh
# Author: wenjie
# Organization: [email protected]
##############################################################
. /etc/init.d/functions


case $1 in
    start)
        #启动要考虑什么问题   是否未启动     是否已启动
        rsync_status=$(pidof rsync |wc -l)          #检查进程是否启动  1  启动    0 未启动
        if [ $rsync_status -eq 0 ];then
            rsync --daemon
            action "rsync 启动成功" /bin/true
        else
            action "rsync 已经启动" /bin/false
        fi
        ;;
    stop)
        #考虑问题     已经启动,正常停止即可。   服务没有启动,停止直接提示没启动。
        rsync_status=$(pidof rsync |wc -l)          #检查进程是否启动  1  启动    0 未启动
        if [ $rsync_status -eq 1 ];then
            pkill rsync
            action "rsync 停止成功" /bin/true
        else
            action "rsync 暂未启动" /bin/false
        fi
        ;;
    restart)
        #拷贝问题
               # ( 服务已经启动的情况下,可以实现先停止后启动)
               #( 服务没有启动,需要重启怎么办?   不停止,只启动 )

        rsync_status=$(pidof rsync |wc -l)          #检查进程是否启动  1  启动    0 未启动
        if [ $rsync_status -eq 1 ];then
            #正常流程,停止,启动即可。
            pkill rsync
            sleep 1					#等待1s
            rsync --daemon
            action "Rsync 重启成功" /bin/true

        elif [ $rsync_status -eq 0 ];then
            action "Rsync 暂未启动" /bin/false
            echo "--------尝试启动-------------"
            sleep 1
            rsync --daemon
            action "Rsync 重启成功" /bin/true
        fi
        ;;
    *)
        echo "USAGE: sh  $0 [ start | stop | restart ]"
        exit
esac
  • 4.编写脚本,根据用户输入的服务名称查询该服务的状态,如果服务不存在则直接报错。如果服务启动则提示 [重启和停止操作],如果服务没有启动则提示 [启动和取消操作]

  • sh check_service.sh httpd	 | nginx
    1.先判断查询的服务是否存在,如果不存在则直接报错。
    [root@web01 shell-case]# systemctl status httpddad
    Unit httpddad.service could not be found.
    [root@web01 shell-case]# echo $?
    4
    
    2.如果服务存在并且是启动状态
    		提示: 重启还是停止,需要用户 交互的输入
    [root@web01 shell-case]# systemctl status httpd
    ● httpd.service - The Apache HTTP Server
       Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
       Active: active (running)
         Docs: man:httpd(8)
               man:apachectl(8)
    [root@web01 shell-case]# echo $?
    0
    		
    3.如果服务没有启动
    		提示: 启动还是取消
    [root@web01 shell-case]# systemctl status httpd
    ● httpd.service - The Apache HTTP Server
       Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
       Active: inactive (dead)
         Docs: man:httpd(8)
               man:apachectl(8)
    [root@web01 shell-case]# echo $?
    3
    
    
    
    
    [root@web01 shell-case]# cat case-9.sh
    #!/bin/bash
    ##############################################################
    # File Name: case-9.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    . /etc/init.d/functions
    
    #查询服务仅能root用户执行
    if [ $UID -ne 0 ];then
        echo "$USER$0 脚本没有权限"
        exit
    fi
    
    #确保用户仅能传递一个参数
    if [ $# -ne 1 ];then
        echo  "USAGE: $0 Service_Name [ nginx | httpd | vsftpd | rsyncd | ... ]"
        exit
    fi
    
    
    
    systemctl status $1 &>/dev/null
    rc=$?														#将$?的结果存储至rc变量中,这样rc变量中就是$?的结果不会发生任何变化
    
    if [ $rc -eq 4 ];then
        echo "Unit $1  could not be found."
    
    elif [ $rc -eq 0 ];then
        read -p "当前 $1 服务已是启动状态,请问需要 [ restart | stop ]: " action
        case $action in
            restart)
                systemctl restart $1
                action "$1 restart ok" /bin/true
                ;;
            stop)
                systemctl stop $1
                action "$1  stop ok" /bin/true
                ;;
            *)
                echo "输入指令错误..."
                exit
        esac
    elif [ $rc -eq 3 ];then
        read -p "当前 $1 服务暂未启动,请问需要  [ start | quit ]: " action2
        case $action2 in
            start)
                systemctl start $1
                action "$1 start ok" /bin/true
                ;;
            quit)
                exit
                ;;
            *)
                echo "输入指令错误..."
                exit
        esac
    else
        echo "$0 脚本无法判断当前服务是什么情况,自动退出了"
        exit
    fi
    

    本周三天内容:

    ​ 1.变量

    ​ 2.if

    ​ 3.case

    下周:

    ​ 1.for循环、while循环、(break、continue、exit、)、functions函数、shell数组 2天

    ​ 2.正则表达式、grep、sed、awk、数组 3天

使用 grep正则表达式方式,匹配 a b c 三类IP地址。
10.0.0.0 ~ 10.255.255.255
172.16.1.0 ~ 172.16.31.254
192.168.1.0 ~ 192.168.255.255

[root@web01 shell-case]# cat test.sh
#!/bin/bash
##############################################################
# File Name: test.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

read -p "请输入需要校验的IP地址: " Action
if [[ $Action =~ ^(10)\.([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.([0-9]|[1-9][0-9]|[1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])$ ]];then
        echo " $Action 属于A类地址"

    elif [[ $Action =~ ^(172)\.([1][6-9]|[2][0-9]|[3][0-1])\.([0]|[1][0-9]{0,2}|[2][0-9]|[2][0-4][0-9]|[2][0-5][0-5]|[3-9][0-9])\.([0]|[1][0-9]{0,2}|[2][0-9]|[2][0-4][0-9]|[2][0-5][0-5]|[3-9][0-9])$ ]];then
            echo "$Action 属于B类地址"

	elif [[ $Action =~ ^(192)\.(168)\.([0]|[1][0-9]{0,2}|[2][0-9]|[2][0-4][0-9]|[2][0-5][0-5]|[3-9][0-9])\.([0]|[1][0-9]{0,2}|[2][0-9]|[2][0-4][0-9]|[2][0-5][0-5]|[3-9][0-9])$ ]];then
                echo "$Action 属于C类地址"

	else
    			echo "$Action 不属于地址"
 fi
  • 循环:
    • 1.什么是循环
    • 2.for循环
    • 3.for循环语法
    • 4.for循环脚本
    • 5.while循环
    • 6.while示例脚本
    • 7.关键字 break、continue、exit
  • 函数、shell数组 ( 上午足够 )
    • 1.函数内容
    • 2.脚本改造为函数的方式
    • 3.shell数组是什么、shell数组的遍历与循环(!!不是太好理解,也不重要,但是起码要能得懂。为后面学习awk数组做铺垫 )
  • 周三:
    • 正则表达式 ( 通过一系列的符号!@#$%^,去匹配一组字符串 =~ 正则匹配 )
    • grep、sed
  • 周四周五:
    • awk基础知识
    • awk数组

5.1for循环

  • 1.什么是循环:

    • 重复去完成一个任务。循环在shell脚本中有什么使用的场景:
      • 比如:每隔5分钟执行一次ping操作,可以使用定时任务,我们还可以使用循环的方式。
      • 比如:每隔5分钟执行一次ping操作,ping的操作只执行100次,循环方式来实现。
  • 2.什么是for循环:

    • for循环也叫条件循环,假设给5个条件,那么我的for循环就会循环5次。结束后,脚本退出。
  • 3.for循环基础语法示例

    • for 变量名 in [ 取值列表 ]
      do
      		循环体需要执行的内容
      done
      
      
      for var in test1 test2 test3
      do
      	echo 123						#请问123会输出几次  3次(给予可三个条件)
      	echo This is $var		#结果是啥
      done
      
      
      #给了4个条件还是6个条件
      for var in file1 "file2 file3" file4 "hello world"
      do
        echo the text is $var
      done
      
      #为list变量赋予了三个值
      list="file1 file2 file3"
      # 循环list变量,将list变量中的值挨个复制给 i 变量
      for i in $list
      do
        echo var is $i			
      done
      
      
      
      for i in $(cat /etc/hosts)
      do
        echo "$i"
      done
      
      
      
      #语法格式
      for ((i=0;i<10;i++))
      do
         commmands
      done
      
      #第一步先执行 i=0
      #第二部执行  0<10
      #第三部执行  commands命令
      #第四部执行  i++    =1 
      #接下来就重复  第二部-->第四部  ---直到条件最终不成立停止
      
      
      [root@bgx shell]# sh for-9.sh
      num is 1 9
      num is 2 8
      num is 3 7
      num is 4 6
      num is 5 5
      num is 6 4
      num is 7 3
      num is 8 2
      num is 9 1
      
      [root@web01 shell-for]# cat for06.sh
      #!/bin/bash
      a=0
      b=10
      
      for i in {1..9}
      do
          let a++;
          let b--;
          echo Number is $a $b
      done
      
      
      [root@web01 shell-for]# cat for07.sh
      #!/bin/bash
      for (( a=1,b=9;a<10;a++,b--))
      do
          echo num is $a $b
      done
      
    需求1:批量探测某个网段的主机存活状态,将存活的主机存入ok.txt文件中。
    
    [root@web01 shell-for]# cat for08.sh
    #!/bin/bash
    ##############################################################
    # File Name: for08.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    # 10.0.0.0/24
    for i in {1..254}
    do
        {
            ip=10.0.0.$i
            ping -c1 $ip &>/dev/null
            if [ $? -eq 0 ];then
                echo "$ip 存活"
            fi
        }&
    done
    
    需求2:判断主机存活状态,要求判断三次,如果三次失败则失败。
    
    [root@web01 shell-for]# cat for09.sh
    #!/bin/bash
    ##############################################################
    # File Name: for08.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    for i in {1..254}
    do
        {
            ip=10.0.0.$i
            ping -c1 $ip &>/dev/null
            if [ $? -eq 0 ];then
                echo "$ip 存活"					>>ok.txt
            else															#如果ip不存活,则进入else阶段
                for j in {1..3}								#循环总共要运行3次(如果三次都结束就退出当前的循环)
                do
                    ping -c1 $ip &>/dev/null
                    if [ $? -eq 0 ];then
                        echo "探测$ip $j 次,成功"   >> ok.txt
                        break   #退出本次循环
                    else
                        echo "探测$ip $j 次,还是失败" >> err.txt
                    fi
                done
            fi
        }&
    done
    
    
    需求3: 嵌套循环:
    现在有一个ip.txt的文件,里面有很多IP地址。
    还有一个port.txt的文件,里面有很多端口号。
    现在希望对ip.txt的每个IP地址进行端口的探测,探测的端口号来源于port.txt文件中,最后将开放的端口和IP保存到一个ok.txt文件。
    #ip.txt                         port.txt
    10.0.0.1                        80
    10.0.0.2                        22
    10.0.0.3                        3306
    10.0.0.4                        23
    10.0.0.5                        443
    10.0.0.6                        9000
    10.0.0.7                        123
    10.0.0.8                        6379
    10.0.0.9                        10050
    172.16.1.5                      10051
    192.168.10.1
    172.16.1.6
    
    #1.拿到ip.txt中的第一个IP地址。
    #2.基于已经拿到的IP进行端口的探测。
    nc -z 10.0.0.7 80
    
    [root@web01 shell-for]# cat ip.txt
    10.0.0.1
    10.0.0.2
    10.0.0.3
    10.0.0.4
    10.0.0.5
    10.0.0.6
    10.0.0.7
    10.0.0.8
    10.0.0.9
    10.0.0.31
    10.0.0.51
    172.16.1.7
    172.16.1.8
    172.16.1.51
    172.16.1.5
    192.168.10.1
    172.16.1.6
    
    [root@web01 shell-for]# cat port.txt
    80
    22
    3306
    23
    443
    9000
    123
    6379
    10050
    10051
    
    [root@web01 shell-for]# cat for15.sh
    #!/bin/bash
    ##############################################################
    # File Name: for15.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    #第一层循环
    for ip in $(cat ip.txt)
    do
        {
        ping -c1 $ip &>/dev/null
        if [ $? -eq 0 ];then
            #第二次循环
            for port in $(cat port.txt)
            do
                nc -z -w 1 $ip $port &>/dev/null
                if [ $? -eq 0 ];then
                    echo "$ip $port" >> ok.txt
                fi
            done
        else
            echo "$ip 不通所以没有进行端口探测.."
        fi
        }&
    done
        wait			#等待任务执行完毕后,在释放窗口的操作
    
    
    需求4:获取系统的所有用户并输出。效果如下:
    This is 1 user: root
    This is 2 user: bin
    This is 3 user: daemon
    This is 4 user: adm
    ...............
    
    [root@web01 shell-for]# cat for10.sh
    #!/bin/bash
    ##############################################################
    # File Name: for10.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    #1.设定i变量初始值为1
    i=1
    for user in $(awk -F ":" '{print $1}' /etc/passwd)
    do
        echo This is $i user: $user
        let i++		#让变量进行自增+1
    done
    
    需求5:批量创建100个用户,比如输入wenjie则会创建wenjie001-100。
    	1.交互输入还是脚本传参   read  |  $1
    	2.用户填写wenjie
    	3.执行for循环进行批量创建用户
    	
    [root@web01 shell-for]# cat for11.sh
    #!/bin/bash
    ##############################################################
    # File Name: for11.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    . /etc/init.d/functions
    
    read -p "请输入你要创建的用户名称: " us
    
    for i in {001..100}
    do
        #将用户传递的名称+编号组成需要创建的用户名称
        username=${us}${i}
    
        id $username &>/dev/null
        if [ $? -eq 1 ];then
            useradd $username
            action "$username is create ok" /bin/true
        else
            action "$username already exists" /bin/false
        fi
    
    done
    
    需求6:批量删除100个用户,比如输入wenjie则会删除wenjie001-100。
    [root@web01 shell-for]# cat for12.sh
    #!/bin/bash
    ##############################################################
    # File Name: for11.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    . /etc/init.d/functions
    
    read -p "请输入你要创建的用户名称: " us
    
    for i in {001..100}
    do
        #将用户传递的名称+编号组成需要创建的用户名称
        username=${us}${i}
    
        id $username &>/dev/null
        if [ $? -eq 0 ];then
            userdel $username
            action "$username is delete ok" /bin/true
        else
            action "$username is delete err" /bin/false
        fi
    done
    
    
    # case+for+基础命令
    sh user.sh add wenjie   #创建了100个用户
    sh user.sh del wenjie  #删除了100个用户
    需要在执行脚本时传递两个参数:
    	$1 = add | del
    	$2 = username
    
    1.使用case 来判断 $1 
    	add
    			添加的操作
    	del
    			删除的操作
    [root@web01 shell-for]# cat for13.sh
    #!/bin/bash
    ##############################################################
    # File Name: for13.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    . /etc/init.d/functions
    
    if  [ $# -ne 2 ];then
        echo "请在执行脚本时进行参数传递 [ --del Username | --add Username ] "
        exit
    fi
    
    case $1 in
        add|--add)
            for i in {1..100}
            do
                username=$2$i
                useradd $username &>/dev/null
                if [ $? -eq 0 ];then
                    action "添加 $username 成功" /bin/true
                else
                    action "添加 $username 失败" /bin/false
                fi
            done
            ;;
        del|--del)
            for i in {1..100}
            do
                username=$2$i
                userdel $username &>/dev/null
                if [ $? -eq 0 ];then
                    action "删除 $username 成功" /bin/true
                else
                    action "删除 $username 失败" /bin/false
                fi
            done
            ;;
        *)
            echo "USAGE: sh $0 [ --add | --del | add | del ]"
            exit
    esac
    
    
    # 通过读入文件中的用户与密码文件,进行批量添加用户。文件中的格式: user:passwd
    [root@web01 shell-for]# cat user.txt
    xiaohong:123
    xiaolan:456
    xiaotian:789
    xiaowang:012
    xiaogou:345
    
    #1.使用for循环如何读入文件内容:
    #2.for循环如何将这里的每一列进行拆分
    
    
    [root@web01 shell-for]# cat for14.sh
    #!/bin/bash
    ##############################################################
    # File Name: for14.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    for i in $(cat user.txt)
    do
        user=$(echo $i | awk -F ":" '{print $1}')			#将一行中的第一列赋值给user变量
        pass=$(echo $i | awk -F ":" '{print $2}')			#将一行中的第二列赋值给pass变量
    
        #创建用户
        useradd $user &>/dev/null && \
        echo "$pass" | passwd --stdin $user &>/dev/null
        if [ $? -eq 0 ];then
            echo "$user 创建成功."
        else
            echo "$user 创建失败."
        fi
    done
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wjQo6lpT-1594120060840)(Shell编程实践.assets/image-20200608114735663.png)]

5.2while循环

  • 1.什么是while循环:

    • 和for循环一样,也是做循环的。
  • 2.while循环,for循环,什么情况下使用while、什么情况下使用for

    • 1.知道循环次数的情况下使用for,比如一天循环24次。
    • 2.不知道要循环多少次,那么就使用while,比如弄一个猜数字的脚本游戏,每个人猜对的次数是未知的。
      • 死循环、就是一直循环下去,那么这种场景也是选择while循环。 ( 公交汽车 )
  • while循环基础语法

    • while 条件测试     (条件为真,就执行循环体)
      do
      	循环体要执行的内容
      done
      
      
      [root@web01 shell-while]# sh while01.sh
      number is 10
      number is 9
      number is 8
      number is 7
      number is 6
      number is 5
      number is 4
      number is 3
      number is 2
      number is 1
      
      [root@web01 shell-while]# cat while01.sh
      #!/bin/bash
      ##############################################################
      # File Name: while01.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      var=10
      
      while [ $var -gt 0 ]
      do
          echo "number is $var"
          var=$[ $var -1 ]        #将重新复制给var变量
      done
      
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xqia0gYW-1594120060842)(http://cdn.xuliangwei.com/15532328984237.jpg)]

[root@web01 shell-while]# cat while02.sh
#!/bin/bash
##############################################################
# File Name: while02.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

num=9   #设定一个初始变量

while [ $num -ge 1 ]        #如果num变量大于0则执行
do
    echo "$num * $num = $[ $num * $num ]"       # 9 * 9 = 80
    num=$[ $num -1 ]                            # num=8

done

作业:

9 * 1		= 9
8 * 2		= 16
7 * 3		= 21
6 * 4		= 24
5 * 5		= 25
4 * 6
3 * 7
2 * 8
1 * 9

[root@web01 shell-while]# cat while03.sh
#!/bin/bash
##############################################################
# File Name: while03.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

a=9
b=1

while [ $a -ge 1 ]
do
    echo "$a * $b = $[ $a * $b ]"

    #自减
    a=$[ $a -1 ]
    #自增
    b=$[ $b +1 ]
done

[root@web01 shell-while]# sh while03.sh
9 * 1 = 9
8 * 2 = 16
7 * 3 = 21
6 * 4 = 24
5 * 5 = 25
4 * 6 = 24
3 * 7 = 21
2 * 8 = 16
1 * 9 = 9
  • 循环嵌套整数比对,判断用户输入的数值是否大于0,如果大于0,则三秒输出一次大于。

    • [root@web01 shell-while]# cat while04.sh
      #!/bin/bash
      ##############################################################
      # File Name: while04.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      read -p "请输入数字: " num
      
      while [ $num -ge 0 ]
      do
          echo "大于"
          sleep 3
      done
      
  • 循环嵌套文件比较,判断/tmp/wenjie文件是否存在,如果不存在则3s输出一次 not found。如果存在自动退出。

    • [root@web01 shell-while]# cat while05.sh
      #!/bin/bash
      ##############################################################
      # File Name: while05.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      while [ ! -d /tmp/wenjie ]
      do
          echo "not found /tmp/wenjie"
          sleep 3
      done
      
  • 循环嵌套字符比较,判断用户输入的用户名,如果不是root则一直让其输入

    • [root@web01 shell-while]# cat while06.sh
      #!/bin/bash
      ##############################################################
      # File Name: while06.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      
      read -p "请输入用户名称: " account
      
      while [ $account != "root" ]
      do
          read -p "请输入用户名称: " account
      done
      

5.3 循环中的关键字 break、continue、exit

  • 在我们使用循环语句进行循环的过程中,有时候需要在未达到循环结束条件时候,强制跳出该循环。

  • 比如:原本要循环10次,但是我可以在第五次执行完成后退出循环。

  • 1.exit,退出脚本。退出程序。当脚本碰到了exit时,直接退出,剩余不管有多少代码都不执行。

    • [root@web01 shell-while]# cat while07.sh
      #!/bin/bash
      ##############################################################
      # File Name: while07.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      
      for i in {1..3}
      do
          echo "123"
          exit        #退出脚本,不管后面还有多少代码。
          echo "456"
      done
      
          echo "Done...."
      
  • 2.break, 结束当前循环,但会执行循环之后的所有代码。

    • [root@web01 shell-while]# cat while07.sh
      #!/bin/bash
      ##############################################################
      # File Name: while07.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      
      for i in {1..3}
      do
          echo "123"
          break       #跳出当前循环,但当前循环以外的代码都会被执行。
          echo "456"
      done
      
          echo "Done...."
      
  • 3.continue, 忽略本次循环剩余的所有代码,直接进行下一次循环,直到循环结束,然后继续执行循环以外的代码。

    • [root@web01 shell-while]# cat while07.sh
      #!/bin/bash
      ##############################################################
      # File Name: while07.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      
      for i in {1..3}
      do
          echo "123"
          continue
          #
          echo "456"
      done
      
          echo "Done...."
      
  • 4.演示break和continue的使用案例(小脚本)

    • 循环嵌套continue,打印1-9当数值为5则跳过本次循环,继续下一次循环。请分别使用for和while实现。
      [root@web01 shell-while]# cat while08.sh
      #!/bin/bash
      ##############################################################
      # File Name: while08.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      
      for i in {1..10}
      do
              if [ $i -eq 5 ];then
                  continue
              fi
              echo $i
      done
      [root@web01 shell-while]# sh while08.sh
      1
      2
      3
      4
      6
      7
      8
      9
      10
      
      
      
      [root@web01 shell-while]# cat while09.sh
      #!/bin/bash
      ##############################################################
      # File Name: while09.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      i=11
      
      while [ $i -ge 2 ]
      do
      
          i=$[ $i -1 ]
          if [ $i -eq 5 ];then
              continue
          fi
          echo $i
      done
      
      [root@web01 shell-while]# sh while09.sh
      10
      9
      8
      7
      6
      4
      3
      2
      1
      
      
      循环嵌套break,打印1-9当数值为5则停止。请分别使用for和while实现。
      
      [root@web01 shell-while]# cat while010.sh
      #!/bin/bash
      ##############################################################
      # File Name: while010.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      for i in {1..9}
      do
          if [ $i -eq 5 ];then
              break
          fi
          echo $i
      done
      

5.4 while练习

1.使用while读入文件方式,批量创建用户
	1.必须得有一个用户的文件。
	2.如何使用while读入文件。
	
[root@web01 shell-while]# cat while10.sh
#!/bin/bash
##############################################################
# File Name: while10.sh
# Author: wenjie
# Organization: [email protected]
##############################################################
. /etc/init.d/functions

#将每一行赋值给line
while read line
do
    id $line &>/dev/null
    if [ $? -eq 1 ];then
        useradd $line
        action "$line is ok" /bin/true
    else
        action "$line is err" /bin/false
        continue
    fi
done<user.txt

2.使用while读入文件方式,批量创建用户以及密码
[root@web01 shell-while]# cat while11.sh
#!/bin/bash
##############################################################
# File Name: while11.sh
# Author: wenjie
# Organization: [email protected]
##############################################################
. /etc/init.d/functions

while read line
do
    user=$(echo $line | awk -F ":" '{print $1}')
    pass=$(echo $line | awk -F ":" '{print $2}')

    #创建用户前,先判断用户是否存在
    id $user &>/dev/null
    if [ $? -eq 1 ];then        #$?等于1表示该用户没有被创建
        useradd $user && \
        echo "$pass" | passwd --stdin $user &>/dev/null
        action "$user Create Ok" /bin/true
    else
        action "$user Create Error" /bin/false
        continue
    fi
done<user.txt



3.示例: 猜数字游戏
1)随机输出一个1-100的数字					echo $(($RANDOM%100))
2)要求用户输入的必须是数字(数字处加判断)
3)如果比随机数小则提示比随机数小了 大则提示比随机数大了
4)正确则退出 错误则继续死循环
5)最后统计猜了多少次(猜对了多少次,失败多少次)


[root@web01 shell-while]# cat while12.sh
#!/bin/bash
##############################################################
# File Name: while12.sh
# Author: wenjie
# Organization: [email protected]
##############################################################
sj=$(echo $(($RANDOM%100)))

#作弊器开关
#echo $sj

#计数器
count=0

while true
do
    read -p "猜数字游戏,请输入摇奖号码: " num

    #回车
    if [ -z $num ];then
        continue
    fi

    #字母
    if [[ ! $num =~ ^[0-9]+$ ]];then
        echo "请输入整数 [0-100]"
        continue
    fi

    #自增这个count的变量
    count=$[ $count +1 ]

    #比对:sj变量的值,与 用户输入的值是否一致
    if [ $sj -eq $num ];then
        echo "恭喜你才对了...."
        echo "你总共猜了 $count 次,失败了 $[ $count -1 ]"
        exit
    else
        if [ $sj -ge  $num ];then
            echo "你猜的太小了,重新来把..."
        else
            echo "你猜的太大了,重新来把...."
        fi
    fi
done

5.5课后练习题

  • 1.用SH 脚本 筛选 [ 2.txt 在 1.txt里 ] 没有的IP 。

    • 2.txt
      	10.0.0.1
      	10.0.0.2
      	
      1.txt
      	10.0.0.3
      	10.0.0.2
      	10.0.0.4
      
      
      [root@web01 shell-while]# cat while.sh
      #!/bin/bash
      ##############################################################
      # File Name: while.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      
      for i in $(cat 2.txt)
      do
          #拿到该IP地址,去过滤1,txt文件,统计结果,如果为1说存在,如果为0说明不存在。
          file=$(grep "$i" 1.txt |wc -l)
          if [ $file -eq 0 ];then
              echo "$i"
          fi
      done
      
  • 2.使用for循环备份mysql库,每个库对应一个sql文件,需要排除没用的。

    • #1.如何提取现在已有的数据库名称。  mysql -uroot -pwenjie.com -e "show databases;" |grep -Ev "_schema|test|Database"
      #2.如何去备份每一个数据库。  mysqldump -uroot -pwenjie.com -B wordpress > /opt/wordpress.sql
      
      [root@db01 ~]# cat while.sh
      #!/usr/bin/bash
      database=$(mysql -uroot -pwenjie.com -e "show databases;" |grep -Ev "_schema|test|Database")
      for db in $database
      do
      	mysqldump -uroot -pwenjie.com -B $db > /opt/${db}.sql
      done
      
  • 3.使用case实现批量删除用户。 wenjie 20 wenjie01~wenjie20

    • 1.提示用户输入需要删除的用户以及删除的个数。
    • 2.如果用户存在则删除,如果不存在则提示no such user
    • [root@web01 shell-while]# cat case-user-delete.sh
      #!/bin/bash
      ##############################################################
      # File Name: case-user-delete.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      . /etc/init.d/functions
      
      read -p "请输入你要删除的用户: " qz
      read -p "请输入你要删除的个数: " hz
      read -p "你要删除的用户是  $qz  删除的总个数是 $hz  ,你确定要删除吗? [ y | n ] " Action
      
      case $Action in
          y)
              for i in $(seq -w $hz)
              do
                  username=$qz$i
                  id $username &>/dev/null
                  if [ $? -eq 0 ];then
                      userdel $username
                      action "$username is delete" /bin/true
                  else
                      action "$username no such user" /bin/false
                  fi
              done
              ;;
          n)
              echo "你已经取消删除操作"
              exit
              ;;
          *)
              echo "请按照提示进行操作..."
              exit
      esac
      
  • 4.循环批量创建用户,需要填入用户的数量、用户的前缀、用户的统一密码(使用read、case、for语句)

  • 填写3个内
    	1.数量   100  
    	2.前缀   wenjie
    	3.密码   123
    需要 3 + 1 read语法       y | n 
    
    
    [root@web01 shell-while]# cat case-user-add.sh
    #!/bin/bash
    ##############################################################
    # File Name: case-user-add.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    . /etc/init.d/functions
    
    read -p "请输入你要创建的用户名称: " user_name
    read -p "请输入你要创建的用户数量: " number
    read -p "请输入你要创建的用户密码: " pass
    read -p "你要创建的用户是  $user_name  你要创建的总数是 $number  所有创建的用户统一密码是: $pass 你确定要创建吗? [ y | n ] "  Action
    
    case $Action in
        y)
            #创建多个用户,同时还要为多个用户设定密码。
            for i in $(seq -w $number)
            do
                username=$user_name$i
                id $username &>/dev/null
                if [ $? -eq 1 ];then
                    useradd $username && \
                    echo "$pass" | passwd --stdin $username &>/dev/null
                    action "$username Create Ok" /bin/true
                else
                    action "$username already exists" /bin/false
                fi
            done
            ;;
        n)
            echo "你选择了退出用户创建,good!"
            exit
            ;;
    esac
    
  • 5.批量创建用户脚本,需要用户输入创建的用户数量(必须是整数),同时还需要用户输入前缀(前缀不能为空)。

    • 例如:前缀wenjie,个数10,代表创建wenjie1~wenjie10,总共10个用户。

脚本:( 函数 + case + if + 循环(for | while) 菜单脚本 )

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TRdxDr1r-1594120060844)(http://cdn.xuliangwei.com/15728633170170.jpg?imageView2/0/q/75%7Cwatermark/2/text/d3d3Lnh1bGlhbmd3ZWkuY29t/font/5qW35L2T/fontsize/500/fill/I0Y4MEEwQQ==/dissolve/100/gravity/East/dx/50/dy/50%7Cimageslim)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zp4ZXxsB-1594120060846)(http://cdn.xuliangwei.com/15728458192245.jpg?imageView2/0/q/75%7Cwatermark/2/text/d3d3Lnh1bGlhbmd3ZWkuY29t/font/5qW35L2T/fontsize/800/fill/I0Y4MEEwQQ==/dissolve/100/gravity/East/dx/50/dy/50%7Cimageslim)]

  • 1.什么是函数

    • 函数就是一组命令的合集,通常用来编写特定的代码模块,供后续重复调用。
  • 2.函数的作用

  • 3.如何定义函数、调用函数

    • #定义,两种方式
      F_Name() {
      		command
      }
      
      function F_Name_2 () {
      	command
      }
      
      #调用
      	F_Name
      	F_Name_2
      
      
      
      [root@web01 shell-functions]# fun1() { echo "hello,Shell"; }
      [root@web01 shell-functions]# fun1
      hello,Shell
      
      [root@web01 shell-functions]# fun1() { echo "hello,$1"; }
      [root@web01 shell-functions]# fun1
      hello,
      [root@web01 shell-functions]# fun1 Linux   #Linux就是第一个参数他会传递给函数中的$1
      hello,Linux
      
  • 4.函数的传参 ( $1 脚本的位置传参 和 函数传参 不是一个意思 )

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-umpKsTvN-1594120060847)(Shell编程实践.assets/image-20200609095151016.png)]

    • 需求1:写一个脚本,该脚本可以实现计算器的功能,可以进行 +-\*/ 四种计算。
      例如: sh cal.sh 30 + 40 | sh cal.sh 30 - 40 | sh cal.sh 30 \* 40 | sh cal.sh 30 / 40*

    • [root@web01 shell-functions]# cat fun03.sh
      #!/bin/bash
      ##############################################################
      # File Name: fun03.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      # 10 - 20
      cal() {
      
      case $2 in
          +)
              echo "$1 + $3 = $[ $1 + $3 ]"
              ;;
          -)
              echo "$1 - $3 = $[ $1 - $3 ]"
              ;;
          x)
              echo "$1 * $3 = $[ $1 * $3 ]"
              ;;
          /)
              echo "$1 / $3 = $[ $1 / $3 ]"
              ;;
          esac
      }
      cal $1 $2 $3
      
      #sh funo3.sh 10 - 20
      
    • 需求2:写一个脚本,实现nginx服务的启动、停止、重启。

    • [root@web01 shell-functions]# cat fun04.sh
      #!/bin/bash
      ##############################################################
      # File Name: fun04.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      #1.先实现功能
      #2.将相同的重复内容抽象并封装到函数中
      #3.优化一下整体脚本
      
      ngx_is_status () {
              systemctl $1 nginx  #3.接收函数传参
      
              if [ $? -eq 0 ];then
                  echo "Nginx Is $1 OK"   #4.接收函数传参
              else
                  echo "Nginx Is $1 Err"
              fi
      }
      
      #1.脚本的位置参数
      case $1 in
          start)
              ngx_is_status $1    #2.将脚本的位置参数解析出来,传给函数
              ;;
          stop)
              ngx_is_status $1
              ;;
          *)
              echo "USAGE: $0 [ start | stop ]"
          esac
      
  • 5.函数的返回值

    • echo 返回数据

    • [root@web01 shell-functions]# cat fun05.sh
      #!/bin/bash
      ##############################################################
      # File Name: fun05.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      
      get_user () {
          users=$(cat /etc/passwd | awk -F ":" '{print $1}')
          echo $users #输出该变量的结果
      }
      
      index=1
      for i in $(get_user)        #函数相当于是命令(所以在调用时要么直接执行,要么$() 执行 )
      do
          echo "This is Number $index:  $i"
          index=$[ $index + 1 ]
      done
      
    • return 返回状态码

    • [root@web01 shell-functions]# cat fun07.sh
      #!/bin/bash
      ##############################################################
      # File Name: fun07.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      #整数比较 (例子,不作为实际使用)
      
      
      cal () {
          if [ $1 -ge $2 ];then
                  return 100
              else
                  if [ $1 -lt $2 ];then
                          return 200
                      else
                          return 300
                  fi
          fi
      }
      cal $1 $2
      rc=$?
      
      if [ $rc -eq 100 ];then
          echo "大于"
      elif [ $rc -eq 200 ];then
          echo "小于"
      elif [ $rc -eq 300 ];then
          echo "等于"
      fi
      
    • 跳板机脚本

    • [root@web01 shell-functions]# cat fun08.sh
      #!/bin/bash
      ##############################################################
      # File Name: fun08.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      meminfo () {
      cat <<-EOF
              -------------------------------
              |       1) db-10.0.0.51      |
              |       2) nfs-10.0.0.31      |
              |       3) web-10.0.0.8     |
              |       h) help                 |
             ---------------------------------
      EOF
      }
          #打印菜单
          meminfo
      
          #不让其执行ctrl+c、ctrl+z
           trap "" HUP INT QUIT TSTP
      
      while true
      do
      
      read -p "请根据编号填写你需要登陆的主机节点: " number
      case $number in
          1)
                  ssh [email protected]
              ;;
          2)
                  ssh [email protected]
              ;;
          3)
                  ssh [email protected]
              ;;
          h)
              meminfo
              ;;
          exec)
              exit
              ;;
          *)
              continue
      
      esac
      done
      
    • 弄一个多级菜单。( 函数、循环、case、if必用。(变量) )

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H0mBOa5V-1594120060849)(Shell编程实践.assets/image-20200609113558445.png)]

[root@web01 shell-functions]# cat fun09.sh
#!/bin/bash
##############################################################
# File Name: fun09.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

mem_info_1 () {
cat <<-EOF
    -----------------------------
    1.Install Nginx
    2.Install PHP
    3.Install MySQL
    4.Quit
    -----------------------------
EOF
}
mem_info_2 () {
cat <<-EOF
    -----------------------------
    1.Install Nginx1.1
    2.Install Nginx1.2
    3.Install Nginx1.3
    4.返回上一层页面
    -----------------------------
EOF
}


    #1.打印1级菜单
    mem_info_1

while true
do
    #2.让用户选择是安装Nginx还是PHP、还是MySQL
    read -p "请根据编号输入对应的数字: " Action_1

    #根据用户选择来调用不同的预案
    case $Action_1 in
            1)
            #打印二级菜单,Nginx版本选择
            mem_info_2
            while true
            do
                 read -p "请根据编号选择你要安装的Nginx版本: " Action_2
                 case $Action_2 in
                     1)
                         echo "Install Nginx 1.11 Done...."
                         ;;
                     2)
                         echo "Install Nginx 1.12 Done...."
                         ;;
                     3)
                         echo "Install Nginx 1.13 Done...."
                         ;;
                     4)
                        clear
                        mem_info_1
                        break
                        ;;
                    *)
                        continue
                 esac
            done
            ;;
        2)
            ;;
        3)
            ;;
        4)
            quit
            ;;
        *)
            continue
    esac
done

shell数组( awk数组 )

必须先学习shell数组( 不是太好理解,用的比较少,所以了解 ),铺垫,在学习awk数组,非常的简单。

  • 1.什么是数组

    • 数组主要是用来存值,只不过可以存储多个值。
  • 2.数组的分类

    • 普通数组: 当一个数组定义多个值,需要取值时,只能通过整数来取值 0 1 2 3 4 5

    • 关联数组:他可以自定义索引名称,当需要取值时,只需要通过 数组的名称[索引] —> 值

      • info ( [name]=wenjie [age]=18 [skill]=linux)  #关联数组(他的索引可以是任意,可以不用是 0 1 2 )
        
        info[skill]
        
        
        
        info {
        		name: wenjie
        		age: 18
        		skill: linux
        
        }
        
        info.skill
        
  • 3.数组如何赋值、如何取值

    • [root@web01 shell-functions]# books=(linux nginx shell)
      [root@web01 shell-functions]# echo ${books[0]}
      linux
      [root@web01 shell-functions]# echo ${books[1]}
      nginx
      [root@web01 shell-functions]# echo ${books[2]}
      shell
      
      #问题:我想取出所有的数据怎么做?  ( 普通数组还是关联数组 方法都一样)
      
      [root@web01 shell-functions]# echo ${info_2[@]}
      wenjie 18 m
      
      [root@web01 shell-functions]# echo ${!info_2[@]}		#取出索引
      name age sex
      
      [root@web01 shell-functions]# echo ${books[@]}
      linux nginx shell
      [root@web01 shell-functions]# echo ${!books[@]}
      0 1 2		#普通数组的索引都是整数
      
      
      
      #普通赋值的两种方式
      [root@web01 shell-functions]# #books=(linux nginx shell)
      [root@web01 shell-functions]# array[0]=pear
      [root@web01 shell-functions]# array[1]=apple
      [root@web01 shell-functions]# array[2]=orange
      [root@web01 shell-functions]#
      
      
      
      #1.必须先申明这是一个关联数组
      [root@Shell ~]# declare -A info
      [root@Shell ~]# declare -A info2
      
      #2.方式一, 关联数组的赋值 (数组名[索引]=变量值 )
      [root@Shell ~]# info[index1]=pear
      [root@Shell ~]# info[index2]=apple
      [root@Shell ~]# info[index3]=orange
      
      #3.方式二, 关联数组的赋值 (数组名=([索引1]=变量值2 [索引2]=变量值2) )
      [root@Shell ~]# info2=([index1]=linux [index2]=nginx [index3]=docker [index4]='bash shell')
      
  • 4.数组的遍历与循环( 重要 )

    • 
      [root@web01 shell-functions]# cat /etc/hosts
      127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
      ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
      
      10.0.0.7 web01
      10.0.0.5 node.wenjie.com
      10.0.0.7 nginx.wenjie.com
      
      
      #为数组进行赋值
      hosts[0]=127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
      hosts[1]=::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
      hosts[2]=10.0.0.7 web01
      hosts[3]=10.0.0.5 node.wenjie.com
      hosts[4]=10.0.0.7 nginx.wenjie.com
      
      
      [root@web01 shell-functions]# sh array01.sh
      你的索引是: 0  该索引对应的值是: 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
      你的索引是: 1  该索引对应的值是: ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
      你的索引是: 2  该索引对应的值是:
      你的索引是: 3  该索引对应的值是: 10.0.0.7 web01
      你的索引是: 4  该索引对应的值是: 10.0.0.5 node.wenjie.com
      你的索引是: 5  该索引对应的值是: 10.0.0.7 nginx.wenjie.com
      
      
      
      
      [root@web01 shell-functions]# cat array01.sh
      #!/bin/bash
      ##############################################################
      # File Name: array01.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      while read line
      do
          #批量赋值(让索引进行自增即可)
          hosts[i++]=$line
          
          #hosts[0]=127.0.0.1   localhost
          #hosts[1]=::1         localhost localhost.localdomain
      done</etc/hosts
      
      #批量取值
      for item in ${!hosts[@]}
      do
          #索引 0 1 2 3 4 5 6                     ${hosts[0]} ${hosts[1]} ${hosts[2]}
          echo "你的索引是: $item  该索引对应的值是: ${hosts[$item]}"
      done
      
      [root@web01 shell-functions]# sh array01.sh
      你的索引是: 0  该索引对应的值是: 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
      你的索引是: 1  该索引对应的值是: ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
      你的索引是: 2  该索引对应的值是:
      你的索引是: 3  该索引对应的值是: 10.0.0.7 web01
      你的索引是: 4  该索引对应的值是: 10.0.0.5 node.wenjie.com
      你的索引是: 5  该索引对应的值是: 10.0.0.7 nginx.wenjie.com
      
      
      
      统计/etc/passwd文件中,shells类型分别出现了多少次。
      [root@web01 shell-functions]# awk -F ":" '{print $NF}' /etc/passwd | sort  | uniq  -c  | sort -rn
          289 /bin/bash
           33 /sbin/nologin
            1 /sbin/shutdown
            1 /sbin/halt
            1 /bin/sync
            1 /bin/sh
            1 /bin/false
           
        #要统计谁,就将谁作为索引,然后取出他出现的次数就行了。
      [root@web01 shell-functions]# declare -A shells
      [root@web01 shell-functions]# shells[/bin/bash]=0
      [root@web01 shell-functions]# shells[/bin/bash]=1
      [root@web01 shell-functions]# shells[/sbin/nologin]=1
      [root@web01 shell-functions]# let shells[/bin/bash]++
      [root@web01 shell-functions]# let shells[/bin/bash]++
      [root@web01 shell-functions]# let shells[/bin/bash]++
      [root@web01 shell-functions]# let shells[/sbin/nologin]++
      [root@web01 shell-functions]# let shells[/sbin/nologin]++
      [root@web01 shell-functions]# echo ${shells[/bin/bash]}
      4
      [root@web01 shell-functions]# echo ${shells[/sbin/nologin]}
      3
      
      
      [root@web01 shell-functions]# cat array02.sh
      #!/bin/bash
      ##############################################################
      # File Name: array02.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      declare -A shells
      
      while read line
      do
          types=$(echo $line | awk -F ":" '{print $NF}')
          #要统计谁,就将谁作为索引,然后让其自增
          let shells[$types]++
      
      done</etc/passwd
      
      #批量取值
      for item in ${!shells[@]}
      do
          echo "索引是: $item  他出现的次数是: ${shells[$item]}"
      done
      
      
      
      [root@Shell ~]# cat sex.txt
      jack m
      alice f
      tom m
      rose f
      robin m
      bgx m
      
      m 4次
      f 2次
      
      #手动如何实现  (要统计谁,就讲谁作为其索引名称,让其自增,索引对应的值就是该索引出现的次数了。)
      types=$(awk '{print $2}' sex.txt)
      m f m f m m
      	op[m]=4
      	op[f]=2
      	
      	echo ${op[m]}		--》4
      	echo ${op[f]}		--》2
      
      
      #脚本如何实现
      [root@web01 shell-functions]# cat array03.sh
      #!/bin/bash
      ##############################################################
      # File Name: array03.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      declare -A Ops
      
      while read line
      do
          types=$(echo $line | awk '{print $2}')
          #要统计谁,就将谁作为其索引,然后让其自增。
          let Ops[$types]++
      done<sex.txt
      
      for item in ${!Ops[@]}
      do
          echo "你的索引名称是: $item  你索引对应的值是: ${Ops[$item]}"
      
      done
      
      #拆解后的效果
      
      [root@web01 shell-functions]# cat array03.sh
      #!/bin/bash
      ##############################################################
      # File Name: array03.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      declare -A Ops
      
      
      #要统计谁,就将谁作为其索引,然后让其自增。
      while read line
      do
          types=$(echo $line | awk '{print $2}')
          let Ops[$types]++
      
         #假设 m f m m f m   那么赋值之后的结果如下
          # Ops[m]=4
          # Ops[f]=2
      
      done<sex.txt
      
      #           $[!Ops[@]]  =   m f  #所以我们的循环要循环2次
      for item in ${!Ops[@]}
      do
                                # m                      4
                                # f                      2
          echo "你的索引名称是: $item  你索引对应的值是: ${Ops[$item]}"
      
      done
      
      
      
      使用shell数组、或awk数组来。统计一下nginx日志的TOP10的IP地址。   ( Shell数组在统计1MB左右的文件时,效率非常低。)
      
      	1.IP在文件中那一列  假设以  第一列为 IP
      	2.那么就可以将第一列的来源IP作为索引,然后让其自增。
      3.遍历索引,取出对应的值(就是索引出现的次数。)
      [root@web01 opt]# cat array_nginx.sh
      #!/bin/bash
      ##############################################################
      # File Name: array_nginx.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      declare -A Ip
      
      while read line
      do
          types=$(echo $line | awk '{print $1}')
      
          let Ip[$types]++
      
      done<access.log
      
      
      #遍历
      for item in ${!Ip[@]}
      do
              #ip    #值(次数)
          echo $item ${Ip[$item]}
      done
      
      awk数组:
      [root@web01 opt]# time awk '{Ip[$1]++} END { for (item in Ip) print Ip[item],item }' access.log_58
      
      #赋值过程-------------------------------------------------------------------------------------------
      {
      			Ip[$1]++		#要统计谁就将谁作为索引,然后让其自增
      } 
      END 
      
      #遍历取值-------------------------------------------------------------------------------------------
      { 
      			for (item in Ip) 		#遍历数组(默认遍历的是索引名称)
      				print Ip[item],item 
      				#item 是不是就是对应的IP地址信息,也就是存储在数组中的索引
      				#Ip[item]    Ip[10.0.0.2] --->打印Ip数组中这个索引的值(也就是他的次数了)
      }' access.log_58
      
      #1.简单了
      #2.性能比shell数组要高N倍
      
  • 1.正则表达式

    • 1.什么是正则表达式

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MkP5NazA-1594120060851)(Shell编程实践.assets/image-20200610115504626.png)]

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZenKTBME-1594120060852)(Shell编程实践.assets/image-20200610115518286.png)]

    • 2.正则表达式的场景 (# )

    • 3.正则表达式常见语法

    • [root@web01 shell-grep]# grep "^m" test.txt
      my blog is http://liangweilinux.blog.51cto.com
      my qq num is 572891887.
      
      
      [root@web01 shell-grep]# grep -vn "^$" test.txt
      1:I am xuliangwei teacher!
      2:I teach linux.
      3:test
      5:I like badminton ball ,billiard ball and chinese chess!
      6:my blog is http://liangweilinux.blog.51cto.com
      7:our site is http://www.xuliangwei.com
      8:my qq num is 572891887.
      9:not 572891888887.
      
      [root@web01 shell-grep]# grep "." test.txt
      I am xuliangwei teacher!
      I teach linux.
      test
      I like badminton ball ,billiard ball and chinese chess!
      my blog is http://liangweilinux.blog.51cto.com
      our site is http://www.xuliangwei.com
      my qq num is 572891887.
      not 572891888887.
      
      [root@web01 shell-grep]# grep ".*" test.txt
      I am xuliangwei teacher!
      I teach linux.
      test
      
      I like badminton ball ,billiard ball and chinese chess!
      my blog is http://liangweilinux.blog.51cto.com
      our site is http://www.xuliangwei.com
      my qq num is 572891887.
      not 572891888887.
      
      
      [root@web01 shell-grep]# grep "\.$" test.txt
      I teach linux.
      my qq num is 572891887.
      not 572891888887.
      [root@web01 shell-grep]#
      
      [root@web01 shell-grep]# grep "[a-c]" test.txt
      I am xuliangwei teacher!
      I teach linux.
      I like badminton ball ,billiard ball and chinese chess!
      my blog is http://liangweilinux.blog.51cto.com
      our site is http://www.xuliangwei.com
      
      [root@web01 shell-grep]# grep "[0-9]" test.txt
      my blog is http://liangweilinux.blog.51cto.com
      my qq num is 572891887.
      not 572891888887.
      
      [root@web01 shell-grep]# grep "[a-z]" test.txt
      I am xuliangwei teacher!
      I teach linux.
      test
      I like badminton ball ,billiard ball and chinese chess!
      my blog is http://liangweilinux.blog.51cto.com
      our site is http://www.xuliangwei.com
      my qq num is 572891887.
      not 572891888887.
      
      
      [root@web01 shell-grep]# egrep "[0-9]{12}" test.txt
      not 572891888887.
      
      [root@web01 shell-grep]# egrep "[8]{5}" test.txt
      not 572891888887.
      
      [root@web01 shell-grep]# egrep "[8]{2,5}" test.txt
      my qq num is 572891887.
      not 572891888887.
      
    • 4.正则demo示例、实际场景一些需求 grep

      • 需求1:使用grep正则方式方式,提取eth0的IP地址。

      • 数字 10.0.0.1		
        		#10 172 192  至少出现2次,最多3次
        		#至少出现1次,最多出现3次
        		
        [root@web01 shell-grep]# ifconfig eth0 | egrep -o "[0-9]{2,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"|head -1
        10.0.0.7
        
        [root@web01 shell-grep]# ifconfig eth0 | egrep -o "[[:digit:]]{2,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}"|head -1
        10.0.0.7
        
      • 需求2:使用grep正则表达式方式,排除nginx配置文件的空行和#号开头的行。

      • [root@web01 shell-grep]# egrep -v "^$|^#|#" /etc/nginx/nginx.conf
        user www;
        worker_processes  1;
        error_log  /var/log/nginx/error.log warn;
        pid        /var/run/nginx.pid;
        events {
            worker_connections  1024;
        }
        http {
            include       /etc/nginx/mime.types;
            default_type  application/octet-stream;
            log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                              '$status $body_bytes_sent "$http_referer" '
                              '"$http_user_agent" "$http_x_forwarded_for"';
            access_log  /var/log/nginx/access.log  main;
            sendfile        on;
            keepalive_timeout  65;
            include /etc/nginx/conf.d/*.conf;
        }
        
      • 需求3:使用grep正则表达式方式,匹配nginx日志中的http1.0 和http1.1 http2.1 http2.0\统计一下他们出现的次数。

      • 1   1.0  1.1
        2   2.0  2.1
        [root@web01 shell-grep]# egrep -o "HTTP/(1|2)\.(1|0)" access.log_58  | sort |uniq -c
           1650 HTTP/1.0
         165294 HTTP/1.1
              1 HTTP/2.0
        
      • 需求4:使用grep正则表达式方式,匹配zabbix_agentd.conf配置文件中所有已启用的配置。

      • [root@web01 shell-grep]# grep "^[a-Z]" /etc/zabbix/zabbix_agentd.conf
        PidFile=/var/run/zabbix/zabbix_agentd.pid
        LogFile=/var/log/zabbix/zabbix_agentd.log
        LogFileSize=0
        Server=127.0.0.1
        ServerActive=127.0.0.1
        Hostname=web01
        Include=/etc/zabbix/zabbix_agentd.d/*.conf
        
      • 需求5:使用grep正则表达式方式,匹配133、152、166、135开头的手机号码。(写成一个脚本)

      • 1.手机号:必须是11位
        2.开头占了3为,后面只需要8位即可
        
        [root@web01 shell-grep]# egrep "(133|152|166|135)[0-9]{8}" phone.txt
        
        [root@web01 shell-grep]# cat phone.sh
        #!/bin/bash
        ##############################################################
        # File Name: phone.sh
        # Author: wenjie
        # Organization: [email protected]
        ##############################################################
        
        read -p "请输入你的手机号,系统会给你发送短信: " Action
        
        #1.判断用户输入的必须是全整数
        if [[ "$Action" =~ ^[0-9]+$ ]];then
        
            #2.判断用户输入的手机号是否满足133|152|166|135 必须是11位
            if [[ $Action =~ ^(133|152|166|135)[0-9]{8}$ ]];then
                    echo "你输入的 $Action 手机号系统判定合法"
            else
                #3.如果手机号出现了问题,则看是否大于11位、或是小于11、如果都不是则直接提示该手机号位在系统备案
                if [ ${#Action} -gt 11 ];then
                    echo "你输入的手机号超过了11位,请输入正确手机号"
                elif [ ${#Action} -lt 11 ];then
                    echo "你输入的手机号低于11位,请输入正确手机号"
                else
                    echo "你输入的 $Action 手机号未在该系统备案"
                fi
            fi
        else
            echo "你输入的手机号有误。"
            exit
        fi
        
      • 需求6:使用grep正则表达式方式,匹配 qq、163、sina的 email地址。

      • egrep "^([0-9]|[a-z]|[A-Z])+@(qq|sina|163)\.com" mail.txt
        
        
        [root@web01 shell-grep]# cat mail.sh
        #!/bin/bash
        ##############################################################
        # File Name: mail.sh
        # Author: wenjie
        # Organization: [email protected]
        ##############################################################
        
        read -p "请输入你要验证的email [ qq | 163 | sina ]: " Action
        
        if [[ $Action =~ ^([0-9]|_|[a-z]|[A-Z])+@(qq|sina|163)\.com$ ]];then
            echo " $Action 验证成功"
        else
            echo "$Action 验证失败"
        fi
        
      • 需求7

      • 需求8:取出身份证,匹配是哪个省,什么时间出生的,是男还是女,是它们省第几个出生的。
        身份证位数: 18
        最后一位x: 0
        年龄: 从第7位开始到12位
        倒数第二位: 奇数为男 偶数为女
        最后四位: 代表是本省第多少个出生。
        
  • 2.sed

    • 2.1 sed流编辑器
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10XBS2pP-1594120060854)(Shell编程实践.assets/image-20200610141423814.png)]
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a4DDa5KP-1594120060856)(Shell编程实践.assets/image-20200610141525487.png)]
    • 2.2 sed 追加、删除、替换、 pattrn、等等
    #选项:
    [root@web01 shell-sed]# sed -n '/shell/p' test.txt
    I love shell
    
    #-n\-e
    [root@web01 shell-sed]# sed -n -e '/shell/p' -e '/SHELL/p' test.txt
    I love shell
    I love SHELL
    
    #-f
    [root@web01 shell-sed]# cat t.sed
    /shell/p
    [root@web01 shell-sed]# sed -n -f t.sed  test.txt
    I love shell
    
    #-r
    [root@web01 shell-sed]# sed -n -r   '/shell|SHELL/p' test.txt
    I love shell
    I love SHELL
    
    #-i
    [root@web01 shell-sed]# sed  -i 's/shell/Linux/g' test.txt
    [root@web01 shell-sed]# cat test.txt
    I love Linux
    I love SHELL
    This is test file
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0PBD9lR5-1594120060857)(Shell编程实践.assets/image-20200610142220059.png)]

    • 
       1286  cp /etc/passwd ./
       1287  sed -n '10p' passwd
       1288  sed -n '10,20p' passwd
       1289  sed -n '1,+5p' passwd
       1290  sed -n  '/^root/p' passwd
       1291  sed '/^bin/,/^ftp/p' passwd
       1292
       1295  sed '/^bin/,/^mail/p' passwd
       1296  sed -n '/^bin/,/^mail/p' passwd
       1297  sed -n '1,/^mail/p' passwd
        
       本章练习示例:
      1) 打印/etc/passwd中第20行
      	sed -n '20p' passwd
      	
      2)打印/etc/passwd中从第8行开始,到第15行结束的内容
      	sed -n '8,15p' passwd
      
      3)打印/etc/passwd中从第8行开始,然后+5行结束的内容
      	sed -n '8,+5p' passwd
      
      4)打印/etc/passwd中开头匹配bin字符串的内容
      	sed -n '/^bin/p' passwd 
      
      5)打印/etc/passwd中开头为root的行开始,到开头为ftp的行结束的内容
      		sed -n '/^root/,/^ftp/p' passwd
      
      6)打印/etc/passwd中第8行开始,到含有/sbin/nologin的内容的行结束内容
      	sed -n '8,/\/sbin\/nologin/p' passwd
      
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OeKXGaq-1594120060858)(Shell编程实践.assets/image-20200610144618704.png)]

    • [root@web01 shell-sed]# sed -i '40i server{\n\tlisten 80;\n\tserver_name test.com;\n\tindex index.html;\n\t}' /etc/nginx/nginx.conf
      
      
      1) passwd文件第10行后面追加“Add Line”
      	sed -i '10a "Add Line"' passwd
      
      2)passwd文件第10行到第20行,没一行后面都追加 "Test Line"
      	sed -i '10,20a "Test Line"' passwd
      
      3)passwd文件匹配到/bin/bash的行后面追加 "Insert Line"
      	sed -i '/\/bin\/bash/a "Insert Line"' passwd
      	
      4)passwd文件匹配到以bin开头的行,在匹配的行前住家 "Add Line Before"
      	sed -i '/^bin/i "Add Line Before"' passwd
      	
      5)passwd文件每一行前面都追加 “Insert Line Before”
      	sed -i 'i "Insert Line Before"' passwd
      
      6)将/etc/fstab文件的内容追加到passwd文件的第10行后面
      	sed -i '10r /etc/fstab' passwd
      
      7)将/etc/inittab文件内容追加到passwd文件匹配/bin/sync行的后面
      8)将/etc/hosts文件内容追加到passwd文件中10行的后面
      9)将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中
      	sed -n '/\/bin\/bash/p' >> /tmp/sed.txt
      
      10)将passwd文件丛第10行开始,到匹配到nfsnobody开头的所有行内容追加到/tmp/sed-1.txt
      	sed -n '10,/^nfsnobody/p' >> /tmp/sed-1.txt
      
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nxim4I6t-1594120060859)(Shell编程实践.assets/image-20200610150916707.png)]

    • 本章练习示例:
      1)删除/etc/passwd中的第15行
      	sed -i '15d' passwd
      	
      2)删除/etc/passwd中的第8行到第14行的所有内容
      	sed -i '8,14d' passwd
      
      3)删除/etc/passwd中以/sbin/nologin结尾的行
      	sed -i '/\/sbin\/nologin$/d' passwd
      
      4)删除/etc/passwd中以bin开头的行,到以ntp开头的行的所有内容
      	sed -i '/^bin/,/^ntp/d' passwd
      
      5)删除/etc/passwd中第3行到以ftp开头的所有行内容
      	sed -i '3,/^ftp/d' passwd
      	
      6)典型需求:删除Nginx配置文件中所有的注释以及空行
      	sed -ri   '/^#|^$/d' /etc/nginx/nginx.conf
      
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-beigzyK0-1594120060860)(Shell编程实践.assets/image-20200610152155212.png)]

    • 
      #使用sed提取eth0网卡IP
       1409  sed -i '/\/sbin\/nologin/ s#login#LOGIN#g' passwd
       1410  vim passwd
       1411  ser -ri '/^root/,/bin/d' passwd
       1412  sed -ri '/^root/,/bin/d' passwd
       1413  vim passwd
       1414  sed -ri '/^root/,/bin/s#bin#wenjie#' passwd
       1415  vim passwd
       1416  sed -ri '/^root/,/^bin/s#bin#wenjie#' passwd
       1417  vim passwd
       1418  sed -ri '/^ROOT/,/^bin/s#bin#wenjie#' passwd
       1419  vim passwd
       1420  sed -ri '/^ROOT/,/^bin/s#bin#wenjie#g' passwd
       1421  vim passwd
       1422  cat /etc/selinux/config
       1423  sed '/^SeLINUX=/c SeLinux=minimum' passwd
       1424  sed -i '/^SeLINUX=/c SeLinux=minimum' /etc/selinux/config
       1425  vim /etc/selinux/config
       1426  sed -ri '/^SeLINUX=/c SeLinux=minimum' /etc/selinux/config
       1427  vim /etc/selinux/config
       1428  sed -ri '/^SELINUX=/c SeLinux=minimum' /etc/selinux/config
       1429  vim /etc/selinux/config
       1430  sed -ri '/^SELINUX=/c SeLinux=disabled' /etc/selinux/config
       1431  vim /etc/selinux/config
       1432  sed -ri '/^SELINUX=/c SELINUX=disabled' /etc/selinux/config
       1433  vim /etc/selinux/config
       1434  sed -ri '/^SELINUX=.*/c SELINUX=disabled' /etc/selinux/config
       1435  vim /etc/selinux/config
       1436  sed -ri '/^SELINUX=.*/c SELINUX=disabled' /etc/selinux/config
       1437  vim /etc/selinux/config
       1438  sed 's/^/#/' /etc/nginx/nginx.conf
       1439  #sed -i  's/^/#/' /etc/nginx/nginx.conf
       1440  history
      
    • 2.3 sed练习、脚本

    • 需求2:处理一个MySQL配置文件的my.cnf文件。
      1.输文件中有几个段,一对 [ ] 为一段。
      2.针对每个段统计配置文件参数总个数。
      [root@wenjie ~]# sh example.sh
      1: client 2
      2: server 12
      3: mysqld 12
      4: mysqld_safe 7
      5: embedded 8
      6: mysqld-5.5 10

      # this is read by the standalone daemon and embedded servers
      [client]
      port=3306
      socket=/tmp/mysql.socket
      
      #This For server
      [server]
      innodb_buffer_pool_size=8G
      innodb_buffer_pool_instances=8
      innodb_buffer_pool_load_at_startup=1
      innodb_buffer_pool_dump_at_shutdown=1
      innodb_data_file_path=ibdata1:1G:autoextend
      innodb_flush_log_at_trx_commit=1
      innodb_log_buffer_size=32M
      innodb_log_file_size=2G
      innodb_log_files_in_group=2
      innodb_max_undo_log_size=4G
      innodb_undo_directory=undolog
      innodb_undo_tablespaces=95
      
      #this is ysqld stand alone daemon
      [mysqld]
      port=3306
      socket=/tmp/mysql.sock
      basedir=/usr/local/mysql
      datadir=/data/mysql
      pid-file=/data/mysql/mysql.pid
      user=mysql
      bind-address=0.0.0.0
      sort_buffer_size=16M
      join_buffer_size=16M
      thread_cache_size=3000
      interactive_timeout=600
      wait_timeout=600
      
      #This Form ysqld_safe
      [mysqld_safe]
      log-error=/var/log/mariadb/mariadb.log
      pid-file=/var/run/mariadb/mariadb.pid
      max_connections=1000
      open_files_limit=65535
      thread_stack=512K
      external-locking=FALSE
      max_allowed_packet=32M
      
      #this is only for embedded server
      [embedded]
      gtid_mode=on
      enforce_gtid_consistency=1
      log_slave_updates
      slave-rows-search-algorithms='INDEX_SCAN,HASH_SCAN'
      binlog_format=row
      binlog_checksum=1
      relay_log_recovery=1
      relay-log-purge=1
      
      
      #mysqld configure
      [mysqld-5.0]
      key_buffer_size=32M
      read_buffer_size=8M
      read_rnd_buffer_size=16M
      bulk_insert_buffer_size=64M
      myisam_sort_buffer_size=128M
      myisam_max_sort_file_size=10G
      myisam_repair_threads=1
      lock_wait_timeout=3600
      explicit_defaults_for_timestamp=1
      innodb_file_per_table=1
      
      
      
      
      [root@web01 shell-sed]# cat sed.sh
      #!/bin/bash
      ##############################################################
      # File Name: sed.sh
      # Author: wenjie
      # Organization: [email protected]
      ##############################################################
      
      #思路:
      #1.打印每段的内容   sed -n '/\[.*/p' my.cnf | sed -e 's#\[##g' -e 's#\]##g'
      #2.统计每段内容的总参数次数 sed -n  '/^\[server\]/,/^\[.*/p' my.cnf |egrep -v "^#|^\[|^$" | wc -l
      
      #提取每个段的名称
      name=$(sed -n '/\[.*/p' my.cnf | sed -e 's#\[##g' -e 's#\]##g')
      
      #提取每个段的参数总数,但需要传递该段的名称才能获取到他的总数
      mysql_num () {
          sed -n  '/^\['$1'\]/,/^\[.*/p' my.cnf |egrep -v "^#|^\[|^$" | wc -l
      }
      
      index=0
      for item in ${name}
      do
          index=$[ $index +1 ]
          echo  "$index: $item : $(mysql_num $item)"
      done
      

需求1: 处理一个ansible的invtory主机清单。
1.输出主机组,一对 [ ] 为一个主机组。
2.输出每个主机组下的主机总个数。
[root@wenjie ~]# sh example.sh
1: web01: 有 2 台主机
2: web02: 有 12 台主机

扩展需求:

[root@web01 shell-sed]# sh sed_ansible.sh
编号: 1 主机组名称: web 有 5 台主机 , 主机分别是 172.16.1.1 172.16.1.2 172.16.1.3 172.16.1.4 172.16.1.5
编号: 2 主机组名称: db 有 4 台主机 , 主机分别是 172.16.1.8 172.16.1.9 172.16.1.10 172.16.1.11
编号: 3 主机组名称: nfs 有 2 台主机 , 主机分别是 172.16.1.31 172.16.1.32
编号: 4 主机组名称: db01 有 3 台主机 , 主机分别是 172.16.1.51 172.16.1.52 172.16.1.53
编号: 5 主机组名称: backup 有 3 台主机 , 主机分别是 172.16.1.41 172.16.1.42 172.16.1.43

#1.取出主机组名称		sed -n '/\[/p' hosts  | sed -r -e  's#\[##g' -e 's#\]##g'
#2.根据主机组名称在来统计下面的主机数量。  sed -n '/\[db\]/,/\[/p' hosts |egrep -v  "\[.*\]|^$"  | wc -l

[root@web01 shell-sed]# cat sed_ansible.sh
#!/bin/bash
##############################################################
# File Name: sed_ansible.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

#1.取出主机名称:
Host_Name=$(sed -n '/\[/p' hosts  | sed -r -e  's#\[##g' -e 's#\]##g')

#2.通过传参方式将主机组名称传递进来,获取主机的总数。
Host_Total() {
    sed -n '/\['$1'\]/,/\[/p' hosts |egrep -v  "\[.*\]|^$"  | wc -l
}

######################################################
number=0
for item in ${Host_Name}
do
    number=$[ $number + 1 ]
    echo "编号: $number 主机组名称: $item$(Host_Total $item)  台主机"
done





######
[root@web01 shell-sed]# cat sed_ansible.sh
#!/bin/bash
##############################################################
# File Name: sed_ansible.sh
# Author: wenjie
# Organization: [email protected]
##############################################################

#1.取出主机名称:
Host_Name=$(sed -n '/\[/p' hosts  | sed -r -e  's#\[##g' -e 's#\]##g')

#2.通过传参方式将主机组名称传递进来,获取主机的总数。
Host_Total() {
    sed -n '/\['$1'\]/,/\[/p' hosts |egrep -v  "\[.*\]|^$"  | wc -l
}

Host_List () {
    sed -n '/\['$1'\]/,/\[/p' hosts |egrep -v  "\[.*\]|^$" | xargs
}

######################################################
number=0
for item in ${Host_Name}
do
    number=$[ $number + 1 ]
    echo "编号: $number 主机组名称: $item$(Host_Total $item)  台主机 , 主机分别是 $(Host_List $item)"
done

[root@web01 shell-sed]# sh sed_ansible.sh
编号: 1 主机组名称: web      有 5  台主机 , 主机分别是 172.16.1.1 172.16.1.2 172.16.1.3 172.16.1.4 172.16.1.5
编号: 2 主机组名称: db       有 4  台主机 , 主机分别是 172.16.1.8 172.16.1.9 172.16.1.10 172.16.1.11
编号: 3 主机组名称: nfs      有 2  台主机 , 主机分别是 172.16.1.31 172.16.1.32
编号: 4 主机组名称: db01     有 3  台主机 , 主机分别是 172.16.1.51 172.16.1.52 172.16.1.53
编号: 5 主机组名称: backup   有 3  台主机 , 主机分别是 172.16.1.41 172.16.1.42 172.16.1.43 
/tmp/file.txt
#oldboy
 my qq num is 49000448.$

not 4900000448.
my god ,i am not oldbey,but clsn!$
#oldboy
my name is oldboy.$

  not oldman.
 my god ,i am not oldbey,but clsn!$
i like linux



2:在/tmp/file.txt文件中不以#开头的行的行首增加#号
[root@web01 shell-sed]# sed -i  's@^[^#]@\#@g' file.txt

3:用命令行更改/tmp/file.txt文件,把里面所有的“name”更改为“address”
[root@web01 shell-sed]# sed -i  's@name@address@g' file.txt

4:利用sed命令将/tmp/file.txt中所有的回车替换成空格?
[root@web01 shell-sed]# cat file.txt  | xargs
#oldboy #my qq num is 49000448.$ #not 4900000448. #my god ,i am not oldbey,but clsn!$ #oldboy #my address is oldboy.$ # not oldman. # my god ,i am not oldbey,but clsn!$ # i like linux


5:为/tmp/file.txt文件中前2行的行首加#号
[root@web01 shell-sed]# sed -n '1,2s#^#\##gp' file.txt
# oldboy
# my qq num is 49000448.$


6:打印/tmp/file.txt文件中的第5行



7:删除/tmp/file.txt文件中的带特殊字符的行

[root@web01 shell-sed]# sed -i '/[^0-9a-Z ]/d' file.txt
alnum就是:[0-9A-Za-z]
[[:alnum:]]


8:删除#号及#后面的所有空白字符;
[root@web01 shell-sed]# sed -i  '/#/d' file.txt

9:查找/tmp/file.txt文件中1到10行之间,同时将"qq"替换为"we","not"替换"no"
[root@web01 shell-sed]# sed -n -e '1,10s#qq#we#gp' -e '1,10s#not#no#gp'  file.txt


10:使用sed命令打印出/tmp/file.txt文件的第一行到第三行


11:删除文件/tmp/file.txt中所有带有数字的行
	sed -i '/[0-9]/d' file

12:删除/tmp/file.txt文件第3行到第10行的内容?
	sed -i '3,10d' file

13:删除/tmp/file.txt文件中的行首的空白字符。
	sed -i '/^[[:space:]]+/d' file.txt

14:使用sed将/tmp/file.txt文件中第2行的448替换成558
	sed -i '2s#488#588#gp' file.txt
	
15:使用sed将/tmp/file.txt文件中所有$删除
	sed 's#\$##g' file.txt
	
16:将/tmp/file.txt中所有小写字母替换成大写字母
	[root@web01 shell-sed]# sed -r 's#[a-z]#\u&#g' file.txt

17:将/tmp/file.txt文件中第2到第8行之间所有大写字母替换成小写字母
	[root@web01 shell-sed]# sed '2,8s#[A-Z]#\L&#g' file.txt

18:使用sed找出/tmp/file.txt文件中包含oldboy的行

19:将/tmp/file.txt文件中以;结尾的行,行首插入#
[root@web01 shell-sed]# sed -rn '/;$/s#^#\##gp' file.txt
20:将/tmp/file.txt文件中第3和第5行的大写字母替换成小写字母

21:删除/tmp/file.txt文件中第2行到下一个以#号开头的行之间所有空行
[root@web01 shell-sed]# sed -n '2,/^#/p' file.txt  | sed '/^$/d'

22:删除file.txt文件中的空行
	[root@web01 shell-sed]# sed -i '/^$/d' file.txt
	
	
23:删除/tmp/file.txt文件中所有以#开头的行的行首的# 
[root@web01 shell-sed]# sed -n '/^#/p' file.txt | sed 's#\###g'

24:使用sed将selinux彻底关闭
[root@web01 shell-sed]# sed '/SELINUX=/c SELINUX=disabled' /etc/selinux/config


25:修改passwd文件中第4行到第7行中所有的/sbin/nologin为/bin/bash
[root@web01 shell-sed]# sed -n '4,7s#/sbin/nologin#/bin/bash#gp' /etc/passwd

26:把/目录下所有以.txt结尾的文件中包含oldgirl的字符串全部替换为oldboy
sed -i 's#oldtest#old123#g' $(find ./ -type f -name "*.txt")

27:passwd文件的第2、8行前面都追加 "Insert Line Before"    i
28:将passwd文件的内容,添加到/tmp/file.txt文件中第3行的后面  r
29:使用sed命令打印出系统版本
[root@web01 shell-sed]# cat /etc/redhat-release | sed -r 's#(^.*se) (.*) (\(.*)#\2#g'
7.5.1804

30:利用sed 取出ifconfig命令中本机的IPv4地址
[root@web01 shell-sed]# ifconfig eth0| sed -n  -r '2s#(^.*et) (.*) (net.*)#\2#gp'
10.0.0.7

2:在/tmp/file.txt文件中不以#开头的行的行首增加#号

3:用命令行更改/tmp/file.txt文件,把里面所有的“name”更改为“address”
4:利用sed命令将/tmp/file.txt中所有的回车替换成空格?
5:为/tmp/file.txt文件中前2行的行首加#号
6:打印/tmp/file.txt文件中的第5行
7:删除/tmp/file.txt文件中的带特殊字符的行
8:删除#号及#后面的所有空白字符;
9:查找/tmp/file.txt文件中1到10行之间,同时将"qq"替换为"we",“not"替换"no”
10:使用sed命令打印出/tmp/file.txt文件的第一行到第三行
11:删除文件/tmp/file.txt中所有带有数字的行
12:删除/tmp/file.txt文件第3行到第10行的内容?
13:删除/tmp/file.txt文件中的行首的空白字符。
14:使用sed将/tmp/file.txt文件中第2行的448替换成558
15:使用sed将/tmp/file.txt文件中所有$删除
16:将/tmp/file.txt中所有小写字母替换成大写字母
17:将/tmp/file.txt文件中第2到第8行之间所有大写字母替换成小写字母
18:使用sed找出/tmp/file.txt文件中包含oldboy的行
19:将/tmp/file.txt文件中以;结尾的行,行首插入#
20:将/tmp/file.txt文件中第3和第5行的大写字母替换成小写字母
21:删除/tmp/file.txt文件中第2行到下一个以#号开头的行之间所有空行
22:删除file.txt文件中的空行
23:删除/tmp/file.txt文件中所有以#开头的行的行首的#
24:使用sed将selinux彻底关闭
25:修改passwd文件中第4行到第7行中所有的/sbin/nologin为/bin/bash
26:把/目录下所有以.txt结尾的文件中包含oldgirl的字符串全部替换为oldboy
27:passwd文件的第2、8行前面都追加 “Insert Line Before”
28:将passwd文件的内容,添加到/tmp/file.txt文件中第3行的后面
29:使用sed命令打印出系统版本
30:利用sed 取出ifconfig命令中本机的IPv4地址
31:把data目录及其子目录下所有以扩展名.txt结尾的文件中包含oldgirl的字符串全部替换为oldboy.

sed总结:

  • sed

    • 选项:
      • -i 直接变更文件内容
      • -n 取消打印该文件内容
      • -e 进行多个条件的编辑
      • -f 指定一个文件,读取该文件中的sed表达式
      • -r 支持扩展正则表达式
    • pattrn:
      • 相当于根据条件过滤文件内容 。
      • sed也有grep的功能,变更文件内容
    • command:
      • p:打印
      • d:删除 结合-i选项
      • i:在匹配的行前追加内容,或者是在文件的多少行前直接添加
      • a:在匹配的行后追加内容,或者是在文件的多少行后直接添加
      • c:可以通过正则的方式直接替换文件中的内容
      • sg: s/old/new/g 替换 s###g s@@@g
  • 1.awk基本介绍 ( 编程语言 ) 在一个文本文件中,提取我们想要的内容,然后进行(输出 精美)

  • [root@web01 shell-sed]# awk -F ":" 'BEGIN {print 1/2} /^root/ {print $1} END { print "wenjie-over"}' /etc/passwd
    0.5
    root
    wenjie-over
    
    #1.首先执行BEGIN中的操作,1/2 =得到0.5
    #2.执行 /^root/ pattrn 模式匹配,匹配/etc/passwd 以root开头的行   root:x:0:0:root:/root:/bin/bash
    #3.执行command动作,打印第一列,检查FS是否指定字段分隔符,指定了:为分隔符,那么 $1 则是  root
    #4.执行END中的代码,输出wenjie-over
    
    #最终打印出来的结果就是:
    BEGIN:  0.5
    pattrn+command   root
    END   wenjie-over
    
    
    [root@web01 shell-sed]# cat test.awk
    BEGIN{
            print 1/2
            FS=":"
        }
    
        {
            print $1
        }
        
    END{
            print "wenjie-over"
        }
    [root@web01 shell-sed]# awk  -f test.awk  /etc/passwd
    
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RtsaMtN7-1594120060862)(Shell编程实践.assets/image-20200611104909912.png)]

  • 2.awk工作原理

  • 文字版:

    • # awk -F: '{print $1,$3}' /etc/passwd
      
      1.awk将文件中的每一行作为输入, 并将每一行赋给内部变量$0, 以换行符结束
      2.awk开始进行字段分解,每个字段存储在已编号的变量中,从$1开始[默认空格分割]
      3.awk默认字段分隔符是由内部FS变量来确定, 可以使用-F修订
      4.awk行处理时使用了print函数打印分割后的字段
      5.awk在打印后的字段加上空格,因为$1,$3 之间有一个逗号。逗号被映射至OFS内部变量中,称为输出字段分隔符, OFS默认为空格.
      6.awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕.
      
  • 图形版:

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I6UD21UC-1594120060863)(Shell编程实践.assets/image-20200611111919368.png)]

    [root@web01 shell-awk]# #[: ]+
    [root@web01 shell-awk]# #1.连续的多个空格算一个
    [root@web01 shell-awk]# #2.连续的多个:算一个
    [root@web01 shell-awk]# #3. :: 算一个字符
    
  • 3.awk内置变量

    • $0

    • $1 $2 $3

    • FS

    • NF、NR

    • 3.awk内置变量NF,保存每行的最后一列
      #NF: awk字段分隔符之后,他会统计分割后的每一行的总列数。
      
      #1.通过print打印,NF和$NF,你发现了什么?
      [root@wenjie ~]# awk '{print NF,$NF}' awk_file.txt
      5 61
      5 62
      5 63
      5 64
      5 65
      
      #F: 如果将第五行的55置为空,那么该如何在获取最后一列的数字?
      [root@wenjie ~]# awk '{print $5}' awk_file.txt
      61
      62
      63
      64
          #最后一列为空,为什么?
          
      #Q.使用$NF为什么就能成功?(因为NF变量保存的是每一行的最后一列)
      [root@wenjie ~]# awk '{print $NF}' awk_file.txt
      61
      62
      63
      64
      65
      
      #2.如果一个文件很长,靠数列数需要很长的时间,那如何快速打印倒数第二列?
      [root@wenjie ~]# awk '{print $(NF-1)}' awk_file.txt
      51
      52
      53
      54
      90
      
      #------------------------------------------------------------
      4.awk内置变量NR,表示记录行号。
      #------------------------------------------------------------
      
      #1.使用pring打印NR,会发现NR会记录每行文件的行号
      [root@wenjie ~]# awk '{print NR,$0}' awk_file.txt
      1 ll 1990 50 51 61
      2 kk 1991 60 52 62
      3 hh 1992 70 53 63
      4 jj 1993 80 54 64
      5 mm 1994 90    65
      
      #2.那如果我们想打印第二行到第三行的内容怎么办?
      [root@wenjie ~]# awk 'NR>1&&NR<4 {print NR,$0}' awk_file.txt
      2 kk 1991 60 52 62
      3 hh 1992 70 53 63
      
      #2.那如果只想打印第三行,该怎么办?
      [root@wenjie ~]# awk 'NR==3 {print NR,$00}' awk_file.txt
      3 hh 1992 70 53 63
      
      #3.那如果既想打印第三行,又想打印第一列?
      [root@wenjie ~]# awk 'NR==3 {print NR,$1}' awk_file.txt
      3 hh
      
    • RS:读入分隔符,默认是按行读入。\n 认为是一行。

    • [root@wenjie ~]# cat file.txt
      Linux|Shell|Nginx--docker|Gitlab|jenkins--mysql|redis|mongodb
      
      [root@web01 shell-awk]# awk 'BEGIN{RS="--"} {print $0}' file2.txt
      Linux|Shell|Nginx
      docker|Gitlab|jenkins
      mysql|redis|mongodb
      
    • OFS:输出字段分隔符,默认是空格,可以通过调整OFS进行其修改。

    • [root@web01 shell-awk]# awk  'BEGIN{RS="--";FS="|";OFS="::"} {print $1,$3}' file2.txt
      Linux::Nginx
      docker::jenkins
      mysql::mongodb
      
    • ORS、指定输出行分隔符:

    • [root@web01 shell-awk]# awk  'BEGIN{RS="--";FS="|";OFS="::";ORS="===="} {print $1,$3}' file2.txt
      Linux::Nginx====docker::jenkins====mysql::mongodb
      
  • 4.内部变量总结:

    • $0: 每行的内容都会\$0这个变量
    • $1 $2$3 当读入一行内容之后awk会根据分隔符进行自动拆分,并将拆分后的列赋值给$1$2$3
    • FS:指定字段分割符,默认为空格。通常我们会根据需求进行修订。-F BEGIN{FS=""}
    • NF: 当awk通过字段分隔符拆分后,NF会统计拆分后的总列数。
    • NR:当awk读入一行内容后,会将该内容进行编号,赋值给NR变量。
    • RS:读入行分隔符,默认是\n,可以通过BEGIN{RS=}进行修订,但一般不做其修改。
    • OFS:输出字段分割,默认空格,可以修改为任何。BEGIN{OFS=""}
    • ORS:输出行分割符,默认是\n,可以修改为任意。BEGIN{ORS=“”}
  • 4.awk格式化输出print、printf

格式符 含义
%s 打印字符串
%d 打印十进制数(整数)
%f 打印一个浮点数(小数)
%x 打印十六进制数
修饰符 含义
- 左对齐
+ 右对齐
[root@localhost shell]# cat student.txt
wenjie       80    90    96    98
oldqiang    93    98    92    91
oldguo      78    76    87    92
oldli       86    89    68    92
oldgao      85    95    75    90


[root@localhost shell]# cat student.txt
Name       yuwen   shuxue   yuyin  qit
wenjie       80    90    96    98
oldqiang    93    98    92    91
oldguo      78    76    87    92
oldli       86    89    68    92
oldgao      85    95    75    90


[root@web01 shell-awk]# cat student.awk


BEGIN {
    printf "%-10s%-10s%-10s%-10s%-10s\n",
    "Name","Yuwen","Shuxue","yinyu","qita"
    }

    {
    printf "%-10s%-10d%-10d%-10d%-10d\n",$1,$2,$3,$4,$5
    }


[root@web01 shell-awk]# awk -f student.awk student.txt
Name      Yuwen     Shuxue    yinyu     qita
wenjie     80        90        96        98
oldqiang  93        98        92        91
oldguo    78        76        87        92
oldli     86        89        68        92
oldgao    85        95        75        90
  • 5.awk模式匹配 ( 过滤功能 )

1.匹配/etc/passwd文件行中含有root字符串的所有行。

[root@wenjie ~]# awk 'BEGIN{FS=":"}/root/{print $0}' passwd

2.匹配/etc/passwd文件行中以root开头的行。

[root@wenjie ~]# awk '/^root/{print $0}' passwd

3.匹配/etc/passwd文件行中/bin/bash结尾的行。

[root@wenjie ~]# awk '/\/bin\/bash$/{print $0}' passwd
1932  grep "root" /etc/passwd
 1933  awk '/root/' /etc/passwd
 1934  awk '/^root/' /etc/passwd
 1935  awk '/\/bin\/bash$/' /etc/passwd
 1936  awk 'BEGIN{FS=":"} $3<50' /etc/passwd
 1937  awk 'BEGIN{FS=":"} $3<10' /etc/passwd
 1938  awk 'BEGIN{FS=":"} $3<2000' /etc/passwd
 1939  awk 'BEGIN{FS=":"} $3>2000' /etc/passwd
 1940  awk 'BEGIN{FS=":"} $3>9269' /etc/passwd
 1941  grep "/bin/bash" /etc/passwd |wc -l
 1942  awk 'BEGIN{FS=":"} $7=="/bin/bash"' /etc/passwd | wc -l
 1949  awk '/\/bin\/bash/' passwd | wc -l
 1950  awk 'BEGIN{FS=":"} $7=="/bin/bash"' passwd | wc -l
 1951  awk 'BEGIN{FS=":"} $3 ~ /[0-9]{3,}/' /etc/passwd
 1952  head -100 /etc/passwd > passwd
 1953  awk 'BEGIN{FS=":"} $3 ~ /[0-9]{3,}/' passwd
 1954  awk 'BEGIN{FS=":"} $3 ~ /[0-9]{4,}/' passwd
 1955  awk 'BEGIN{FS=":"} $3 ~ /[0-9]{5,}/' passwd
 

 1963  awk 'BEGIN{FS=":"} $1=="ftp" || $1=="mail"' passwd
 1965  awk 'BEGIN{FS=":"} $3<50 && $4>50' passwd
 1967  awk '! /\/sbin\/nologin/' passwd
 1968  awk  '$0 !~ /\/sbin\/nologin/' passwd

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SjqWc0eB-1594120060865)(Shell编程实践.assets/image-20200611160108318.png)]

结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yueLJuLe-1594120060866)(Shell编程实践.assets/image-20200611160137338.png)]

本章练习示例:

1.找出/etc/passwd文件中uid为0的。
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $3==0 ' passwd
root:x:0:0:root:/root:/bin/bash
[root@web01 shell-awk]#

2.找出/etc/passwd文件中uid小于10的。
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $3<10 ' passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

3.找出/etc/passwd文件中uid 小于50,且bash为/bin/bash 的行
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $3<50 && $7="/bin/bash" ' passwd


4.匹配用户名为root并且打印uid小于15的行
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $1 ~ /root/ && $3<15 ' passwd
root:x:0:0:root:/root:/bin/bash
roottttt:x:10:0:root:/root:/bin/bash

5.匹配用户名为root或uid大于5000   || 
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $1 ~ /root/ || $3>50000 ' passwd
root:x:0:0:root:/root:/bin/bash
roottttt:x:10:0:root:/root:/bin/bash
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin

6.匹配uid为3位及以上的行
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} $3 ~ /[0-9]{5,}/ ' passwd

7.匹配到 /sbin/nologin 的行
[root@web01 shell-awk]# awk '/\/sbin\/nologin/' passwd

9.正则匹配nginx开头的行
awk  '$0 ~ /^nginx/'

自行翻译

#
# awk '/west/' datafile 
# awk '/^nor/' datafile 
# awk '$3 ~ /^nor/' datafile 
# awk '/^(no|so)/' datafile 
# awk '{print $3,$2}' datafile
# awk '{print $3 $2}' datafile 
# awk '{print $0}' datafile 
# awk '{print "Number of fields: "NF}' datafile 
# awk '/nor/{print $3,$2}' datafile
# awk '/^[ns]/{print $1}' datafile 
# awk '$5 ~ /\.[7-9]+/' datafile 
# awk '$2 !~ /E/{print $1,$2}' datafile 
# awk '$3 ~ /^job/{print $3 "is a nice boy."}' datafile 
# awk '$8 ~ /[0-9][0-9]$/{print $8}' datafile
# awk '$4 ~ /Cn$/{print "The price is $" $8 "."}' datafile 
# awk '/gdx/{print $0}' datafile 
# awk -F: '{print "Number of fields: "NF}' /etc/passwd 
# awk -F"[ :]" '{print NF}' /etc/passwd



#先猜结果,然后测试。
[root@wenjie ~]# cat b.txt 
wenjie:is a:good boy!

[root@wenjie ~]# awk '{print NF}' b.txt        3
[root@wenjie ~]# awk -F ':' '{print NF}' b.txt  3
[root@wenjie ~]# awk -F"[ :]" '{print NF}' b.txt 5
  • 6.awk条件判断
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} { if ( $3 == 0 ) { print $1,"是管理员administrator"} }' /etc/passwd
root 是管理员administrator

[root@web01 shell-awk]# awk 'BEGIN{FS=":"} { if ($3>999) { i++ } } END { print i,"个普通用户" }' /etc/passwd
292 个普通用户

[root@web01 shell-awk]# awk 'BEGIN{FS=":"} { if ($3>49 && $3<101) { print $0 } }' /etc/passwd
nobody:x:99:99:Nobody:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin

#多条件判断 #if...else 语句格式: {if(表达式){语句;语句;... }else{语句;语句;...}} 

#1.以:为分隔符,判断第三列如果等于0,则打印该用户名称,如果不等于0则打印第七列。
[root@web01 shell-awk]# awk 'BEGIN{FS=":"} { if ($3==0) { print $1 }  else { print $7 }  }' /etc/passwd

#2.以:为分隔符,判断第三列如果等于0,那么则打印管理员出现的个数,否则都视为系统用户,并打印它的个数。
[root@web01 shell-awk]# awk 'BEGIN{FS=":";OFS="\n"} { if($3==0) { i++ } else { j++ } } END { print i" 个管理员" , j" 个系 统用户" }' /etc/passwd
1 个管理员
326 个系统用户


#if elif elif else 
if...else if...else 语句格式: { if(表达式 1){语句;语句;... }else if(表达式 2){语句;语句;. .. }else{语句;语句;... }}


awk 'BEGIN{} { if(){} else if (){} else {} } END {}' /etc/passwd
1.使用awk if打印出当前/etc/passwd文件管理员有多少个,系统用户有多少个,普通用户有多少个
UID=0  管理员
UID >0 && UID <1001 系统用户
UID > 1001  普通用户

[root@web01 shell-awk]# awk 'BEGIN{FS=":";OFS="\n"} { if($3==0){ i++ } else if ($3>0 && $3<1001) { j++ } else { k++ } } END {print i" 个管理员",j" 个系统用户",k" 个普通用户"}' /etc/passwd
1 个管理员
35 个系统用户
291 个普通用户

[root@web01 shell-awk]# cat passwd_count.awk
#行处理前
BEGIN{
    FS=":";OFS="\n"
}

#行处理中
{
    if($3==0)
        { i++ }
    else if ($3>0 && $3<1001)
        { j++ }
    else
        { k++ }
}
#行处理后
END {
    print i" 个管理员",
          j" 个系统用户",
          k" 个普通用户"
}


2.打印/etc/passwd文件中UID小于50的、或者UID小雨50大于100、或者UID大于100的用户名以及UID。
UID<50    		root    	0
UID<50    			bin    1
50<UID<100    nobody    99
50<UID<100    dbus    81
UID>100    		systemd    192
UID>100    			chrony    998	


[root@web01 shell-awk]# cat passwd_uid.awk

BEGIN {
    FS=":"
    printf "%-20s%-20s%-20s\n",
           "Name","User","UID"
}
{
    if ( $3 <50 )
        { printf "%-20s%-20s%-20d\n", "UID<50",$1,$3}

    else if ( $3>50 && $3<100 )
        { printf "%-20s%-20s%-20d\n", "50>UID<100",$1,$3 }

    else
        { printf "%-20s%-20s%-20d\n", "UID>100",$1,$3}
}


3.计算下列每个同学的平均分数,并且只打印平均分数大于90的同学姓名和分数信息

[root@wenjie ~]# cat student.txt
wenjie       80    90    96    98
oldqiang    93    98    92    91
oldguo      78    76    87    92
oldli       86    89    68    92
oldgao      85    95    75    90


[root@web01 shell-awk]# cat student_2.awk
BEGIN {
    printf "%-10s%-10s%-10s%-10s%-10s%-10s\n",
    "Name","Yuwen","Shuxue","yinyu","qita","AVG"
}

{
    total=$2+$3+$4+$5
    avg=total/(NF-1)
}

{
        if ( avg > 90 ) {
            printf "%-10s%-10d%-10d%-10d%-10d%-10d\n",$1,$2,$3,$4,$5,avg
        }
}

4.统计Nginx的状态,请分别打印出200类、300类、400类、500类的状态码出现了多少次。
200-299: 100次
300-399: 200次
400-499: 100次
500+:   20次


[root@web01 shell-awk]# cat nginx_status.awk
BEGIN {
    OFS="\n"
    printf "%-10s%-10s\n",
           "Status","Count"

}
{
    if ($9>=200 && $9<=299)
        { i++ }
    else if ($9>=300 && $9<=399)
        { j++ }
    else if ($9>=400 && $9<=499)
        { k++ }
    else if ($9>=500)
        { l++ }
}

END{
    print "200~299: " i,
          "300~399: " j,
          "400~499: " k,
          "500+: " l
    }
  • 7.awk循环语句

  • while
    for
    
    while循环:while(条件表达式) 动作
    awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'	#输出1-10
    awk -F: '{i=1; while(i<=NF){print $i; i++}}' /etc/passwd
    		1<7  $1
    [root@wenjie ~]#cat b.txt
    111 222
    333 444 555
    666 777 888 999
    
    
    [root@web01 shell-awk]# cat b.awk
    
    {
        i=1
        while ( i<=NF )
            { print $i
                i++
            }
    }
    
    
    
    [root@web01 shell-awk]# cat b.txt |xargs -n1
    111
    222
    333
    444
    555
    666
    777
    888
    999
    
    
    [root@wenjie ~]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }' 
    [root@web01 shell-awk]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }'
    1
    2
    3
    4
    5
    
    awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd
    
    
    需求:计算1+2+3+4+...+100的和,请使用while、for两种循环方式实现
    [root@web01 shell-awk]# cat while.awk
    BEGIN {
            while (i<=100)
            {
                sum+=i      #sum=sum+i
                i++
            }
    
            print "1+2+3+...+100=",sum
    }
    
    [root@web01 shell-awk]# cat for.awk
    BEGIN{
            for(i=1;i<=100;i++)
            {
                sum+=i      #sum=sum+i
            }
            print "1+2+3+...+100=",sum
    }
    
  • 8.awk数组------

  • 1.什么是数组
    2.数组使用场景
    3.数组的语法示例
    4.数组去统计分析Nginx日志
    5.数组的实践案例
    
    
    1.统计/etc/passwd中各种类型shell的数量。
    
    shell数组来做:
    [root@web01 shell-awk]# cat passwd_count.sh
    #!/bin/bash
    ##############################################################
    # File Name: passwd_count.sh
    # Author: wenjie
    # Organization: [email protected]
    ##############################################################
    
    declare -A hosts
    
    #赋值操作
    while read line
    do
        types=$(echo $line|awk 'BEGIN{FS=":"} {print $7}')
    
        let hosts[$types]++
    
    done</etc/passwd
    
    #遍历数组
    for item in ${!hosts[@]}
    do
        echo $item,${hosts[$item]}
    done
    
    
    
    #awk数组来做:
    [root@web01 shell-awk]# awk 'BEGIN{FS=":"} {hosts[$NF]++} END { for (item in hosts) { print item,hosts[item]} }' /etc/passwd
    /bin/sync 1
    /bin/bash 289
    /bin/sh 1
    /sbin/nologin 33
    /sbin/halt 1
    /bin/false 1
    /sbin/shutdown 1
    
    
    [root@web01 shell-awk]# cat passwd_.awk
    BEGIN{
        FS=":"
    }
    
    #赋值操作(因为awk是一行一行读入的,相当是循环了整个文件中的内容)
    {
        hosts[$NF]++
    }
    
    #赋值完成后,需要通过循环的方式将其索引的次数遍历出来
    END {
         for (item in hosts) {
             print item,            #索引名称 /bin/bash  /bin/rsync /sbin/nologin
                   hosts[item]      #索引的值   10         20         30   次数
         }
    }
    
    
    #根据日志实际日志修改2018年01月25日
    
    1.统计2018年01月25日,一天内访问最多的10个IP
    	1.第一列就是IP地址
    	2.统计IP地址出现的次数
    	3.将IP作为索引,然后让其进行自增
    	4.通过循环的方式将每个IP对应的次数进行输出,然后排序,然后 head取前10
    	
    [root@web01 awk_nginx]# cat ngx_top_10
    {
        #要统计谁,就讲谁作为索引,然后让其相同自增,不同则创建。
        cip[$1]++
    }
    
    END{
        for ( item in cip ) {
            print item,cip[item]
        }
    }
    [root@web01 awk_nginx]# awk -f ngx_top_10 access.log_58  | sort -k2 -rn |head
    58.220.223.62 12049
    112.64.171.98 10856
    114.83.184.139 1982
    117.136.66.10 1662
    115.29.245.13 1318
    223.104.5.197 961
    116.216.0.60 957
    180.111.48.14 939
    223.104.5.202 871
    223.104.4.139 869
    
    
    2.统计2018年01月25日,访问大于10000次的IP
    [root@web01 awk_nginx]# cat ngx_top_10
    {
        #设定数组然后让其索引自增
        cip[$1]++
    }
    
    END{
        for ( item in cip ) {
            if (cip[item] > 10000) {
                print item,cip[item]
            }
        }
    }
    
    3.统计2018年01月25日,访问最多的10个页面($request top 10)
    	1.拿到url地址
    	2.打印其被访问的次数
    	3.通过sort排序的方式打印top10
    [root@web01 awk_nginx]# cat ngx_request_top_10
    
    
    {
        request[$7]++
    }
    
    END{
        for ( item in request ) {
            print item,request[item]
    
        }
    }
    [root@web01 awk_nginx]# awk -f ngx_request_top_10 access.log_58 |sort -k2 -rn | head
    /online/api/mc/cart/new/getCart.json 4838
    /online/api/mc/sys/nowTime.json 3859
    /online/mc/crm/integration/points/pointBalance.json 2445
    /online/api/mc/cart/save.json 1872
    /ccbs/global/commonPage/includeHead/contextPath.jsp 1797
    /mobile/theme/ppj/account/tpl/footerTpl.html 1548
    /online/api/mc/productCategory/children.json?language=zh_CN&productCategoryCode=ONLINE_SPECIAL_MENU 1344
    /mobile/theme/ppj/product/tpl/productCategoryTpl.html 912
    /ccbs/global/scripts/jquery/plugins/images/loading.gif 838
    /favicon.ico 810
    
    5.统计2018年01月25日,访问状态码为404及出现的次数($status)
    	1.统计所有的状态码。先输出
    	2.做判断  如果状态码为404  输出)
    
    [root@web01 awk_nginx]# cat ngx_status_top_404
    {
            status[$9]++
    }
    
    END{
        for ( item in status) {
            if (item == 404 ) {
                print item,status[item]
            }
        }
    }
    [root@web01 awk_nginx]# awk -f ngx_status_top_404  access.log_58
    404 3863
    
    
    4.统计每个IP访问状态码数量($status)
    10.0.0.1 200		1次
    10.0.0.1 301		1次
    
    ip_code[10.0.0.1 200]=3
    ip_code[10.0.0.1 200]=1
    
    [root@web01 awk_nginx]# cat ngx_ip_code_top
    {
        ip_code[$1" "$9]++
    }
    
    END{
        for ( item in ip_code ) {
            print item,ip_code[item]
    
        }
    }
    
    7.统计2018年01月25日,每个URL访问内容总大小($body_bytes_sent)
    
    	1.url存储在$7
    	2.size存储在$10
    	
    	/test/1.jpg  20
    	/test/2.jpg  10
    	/test/1.jpg  20
    	/test/2.jpg 10
    	
    	结果
    	/test/1.jpg 40
    	/test/2.jpg 20
    
    
    [root@web01 awk_nginx]# cat ngx_request_size
    
    
    {
        #碰到相同的url自动为一个索引,但是会对其大家进行相加
        url[$7]+=$10
    }
    
    END{
        for ( item in url ){
    
            if ( url[item]/1024/1024 > 50 ) {
                print item,  url[item]/1024/1024"Mb"
            }
        }
    }
    
    
    #awk数组的案例:
    [root@localhost shell]# cat insert.sh 
    #!/bin/bash
    function create_random()
    {
        min=$1
        max=$(($2-$min+1))
        num=$(date +%s%N)
        echo $(($num%$max+$min))
    }
    
    INDEX=1
    while true
    do
        for user in wenjie oldguo oldqiang oldgao oldboy oldli
        do
            COUNT=$RANDOM
            NUM1=`create_random 1 $COUNT`
            NUM2=`expr $COUNT - $NUM1`
            echo "`date '+%Y-%m-%d %H:%M:%S'` $INDEX user: $user insert $COUNT records into datebase:product table:detail, insert $NUM1 records successfully,failed $NUM2 records" >> ./db.log.`date +%Y%m%d`
            INDEX=`expr $INDEX + 1`
        done
    done
    
    2020-06-12 15:11:45 1 user: wenjie insert 31107 records into datebase:product table:detail, insert 14790 records successfully,failed 16317 records
    2020-06-12 15:11:45 2 user: oldguo insert 7714 records into datebase:product table:detail, insert 1739 records successfully,failed 5975 records
    2020-06-12 15:11:45 3 user: oldqiang insert 670 records into datebase:product table:detail, insert 199 records successfully,failed 471 records
    2020-06-12 15:11:45 4 user: oldgao insert 4658 records into datebase:product table:detail, insert 1216 records successfully,failed 3442 records
    
    用户:$5
    总插入数据次数:$7
    成功插入的次数:$13
    失败插入的次数:$16  $(NF-1)
    
    
    需求1:统计每个人分别插入了多少条records进数据库
    [root@web01 awk_mysql]# cat mysql_1
    {
        user[$5]+=$7
    }
    
    END{
        for ( item in user )  {
            print item,user[item]
        }
    }
    
    需求2:统计每个人分别插入成功了多少record,失败了多少record
    [root@web01 awk_mysql]# cat mysql_2
    #统计每个人分别插入成功了多少record,失败了多少record
    
    {
        #两个数组,成功的累计$13 失败的就累计$16
        success[$5]+=$13
        failed[$5]+=$16
    }
    
    END{
        for ( item in success )  {
            print item,success[item],failed[item]
        }
    
    }
    需求3:将需求1和需求2结合起来,一起输出,输出每个人分别插入多少条数据,多少成功,多少失败,并且要格式化输出,加上标题
    [root@web01 awk_mysql]# cat mysql_3
    BEGIN {
        printf "%-20s%-20s%-20s%-20s\n",
               "Name","Success","Failed","Total"
    }
    
    {
        #两个数组,成功的累计$13 失败的就累计$16
        success[$5]+=$13
        failed[$5]+=$16
    }
    
    END{
        for ( item in success )  {
            printf "%-20s%-20d%-20d%-20d\n",
                   item,success[item],failed[item],success[item]+failed[item]
        }
    
    }
    
    需求4:在例子3的基础上,加上结尾,统计全部插入记录数,成功记录数,失败记录数。
    [root@web01 awk_mysql]# cat mysql_4
    #统计每个人分别插入成功了多少record,失败了多少record
    
    BEGIN {
        printf "%-20s%-20s%-20s%-20s\n",
               "Name","Success","Failed","Total"
    }
    
    {
        #两个数组,成功的累计$13 失败的就累计$16
        success[$5]+=$13
        failed[$5]+=$16
    
        #成功$13  失败 $16  total=$7
        total_sum+=$7
        success_sum+=$13
        failed_sum+=$16
    }
    
    END{
        for ( item in success )  {
            printf "%-20s%-20d%-20d%-20d\n",
                   item,success[item],failed[item],success[item]+failed[item]
        }
            printf "%-20s%-20d%-20d%-20d\n",
            "total",success_sum,failed_sum,total_sum
    
    }
    

你可能感兴趣的:(Shell编程实践)