第十一讲 Shell编程

第十一讲 Shell编程

一、正则表达式

  1.1 正则表达式与通配符

    a)正则表达式用来在文件中匹配符合条件的字符串,正则是【包含匹配】。grep、awak、sed等
       命令可以支持正则表达式。
    b)通配符用来匹配符合条件的文件名,通配符是【完全匹配】。ls、find、cp这些命令不支持正则
       表达式,所以只能使用shell自己的通配符进行匹配。

  1.2 基础正则表达式

    
元字符 作用
* 前一个字符匹配0次或任意多次
. 匹配除了换行符外任意一个字符
^ 匹配行首。如:^hello会匹配以hello开头的行
$ 匹配行尾。如:hello$会匹配以hello结尾的行
[]

匹配括号中指定的任意一个字符,只匹配一个字符。例如[aoeiu]匹配任意一个元音字母,

[0-9]匹配任意一位数字,[a-z][0-9]匹配小写字母和一位数字组成的两位字符

[^]

匹配除括号中的字符以外的任意一个字符。如[^0-9]匹配任意一位非数字字符,[^a-z]

表示任意一位非小写字母

\ 转义符。用于取消特殊符号的含义
\{n\}

表示其前面的字符恰好出现n次,例如:[0-9]\{4\}匹配4位数字,[1][3-8][0-9]{9\}

匹配手机号码

\{n,\}

表示其前面的字符出现不小于n次,例如:[0-9]\{2,\}表示两位及以上的数字

\{n,m\}

表示其前面的字符至少出现n次,最多出现m次,例如[a-z]\{6,8\}匹配6到8位小写字母

    
    例如:
      ”*“ 前一个字符匹配0次或任意多次
        grep "a*" test_rule.txt                     #表示匹配所有内容,包含空白行(无意义)
        grep "aa*" test_rule.txt                     #表示匹配至少包含一个a的行
        grep "aaa*" test_rule.txt                     #表示匹配包含两个连续a的字符串
      "." 除了换行符外任意一个字符
        grep "s..d" test_rule.txt                     #会匹配在s和d两个字符之间有两个字符的单词
        grep "s.*d" test_rule.txt                    #会匹配在s和d两个字符之间有任意字符
        grep ".*"                             #匹配所有内容
      "^" 匹配行首,”$“匹配行尾
        grep "^M" test_rule.txt                     #匹配以大写字母M开头的行
        grep "n$" test_rule.txt                      #匹配以n结尾的行
        grep -n "^$" test_rule.txt                   #匹配空白行
      "[]" 匹配括号中指定的任意一个字符,只匹配一个字符
        grep "s[ao]id" test_rule.txt                    #匹配s和i字母中,要么是a,要么是o
        grep "[0-9]" test_rule.txt                    #匹配任意一个数字
        grep "^[a-z]" test_rule                     #匹配用小写字母开头的行
        grep "^[^#]" test_rule                     #匹配不以 #开头的行,可以有效过滤注释
      "[^]" 匹配除括号中的字符以外的任意一个字符
        grep "^[^a-z]" test_rule.txt                   #匹配不以小写字母开头的行
        grep "^[^a-zA-Z]" test_rule.txt                 #匹配不以字母开头的行
      "\" 转义符
        grep "\.$"  test_rule.txt                      #匹配以"."结尾的行
      "\{n\}" 表示前面的字符恰好出现n次
        grep "a\{3\}" test_rule.txt                   #匹配a字母连续出现三次的字符串
        grep "[0-9]\{3\}" test_rule.txt                 #匹配包含连续的三个数字的字符串
      "\{n,\}" 表示其前面的字符出现不小于n次
        grep "^[0-9]\{3,\}[a-z]" test_rule.txt                #表示最少用连续三个数字开头的行
      "\{n,m\}" 表示前面的字符至少出现n次,最多出现m次
        grep "sa\{1,3\}i" test_rule.txt                   #匹配在字母s和字母i之间最少有一个a,最多有三个a   

二、字符截取命令

  2.1 cut字段提取命令

    命令格式:cut [选项] 文件名
      选线:
         -f 列号:      提取第几列(默认按制表符分隔)
         -d 分隔符:    按照指定分隔符分隔列
    例如:
      cut -d ":" -f 1,3 /etc/passwd #以":"分隔,提取第1列和第3列
    注意:cut命令一般和grep命令结合使用,如
       cat /etc/passwd | grep /bin/bash | grep -v root | cut -d ":" -f 1
       #此语句表示查找不为用户名不为root的所有可登录系统用户的用户名
    cut 命令的局限
      如果以空格为分隔符,cut命令不会正确输出想要的结果,此时用awk更合适

  2.2 printf命令

    命令格式:printf ‘输出类型输出格式’ 输出内容
      输出类型:
        %ns    输出字符串,n是数字指代输出几个字符
        %ni     输出整数,n是数字指代输出几个数字
        %m.nf   输出浮点数,m和n是数字,指代输出的整数位和小数位数,如
              %8.2f代表共输出8位数,其中2位是小数,6位是整数
      输出格式:
        \a     输出警告声音
        \b     输出退格键
        \f     清除屏幕
        \n     换行
        \r     回车
        \t     水平制表符
        \v     垂直制表符  
    printf '%s' $(cat student.txt)
    注意:在awk命令的输出中支持print和printf命令
      print:print会在每个输出后自动加入一个换行符(Linux默认没有print命令)
      printf:printf是标准格式输出命令,不会自动加入换行符,需手动加入

  2.3 awk命令

    命令格式:awk '条件1{动作1} 条件2{动作2} ...' 文件名
      条件:一般用关系表达式作为条件
        x>10     判断变量x是否大于10
        x>=10   大于等于
        x<=10   小于等于
      动作:
        格式化输出
        流程控制语句
    例如:
      awk '{printf $2 "\t" $6 '\n'}' student.txt #表示打印第2列和第6列的数据
      df -h | awk '{print $1 "\t" $3 }' 解决cut缺陷
    BEGIN
      awk 'BEGIN {printf "This is a transcript \n"}' #处理第一行数据
      {printf $2 "\t" $6 "\n"} student.txt 
    ES内置变量
      cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=";"} {printf $1 "\t" $3 "\n"}'
    END
      awk 'END{printf "The End \n"} {printf $2 "\t" $4 "\n"}' student.txt
    关系运算符
      cat student.txt | grep -v Name | awk '$4 > 87 {print $2}' #第一行有Name的行需要剔除掉

  2.4 sed命令

    2.4.1 简介

      sed 是一种几乎包括在所有UNIX平台(包括Linux)的轻量级流编辑器。sed主要是用来将数据进行
      选取、替换、删除、新增的命令。优点:支持管道符操作

    2.4.2 命令格式

      sed [选项] '[动作]' 文件名
        选项:
          -n  将经过sed处理的行输出到屏幕
          -e  允许对输入数据应用多条sed命令编辑
          -i   用sed的修改结果直接修改读取数据的文件,而非屏幕输出
        动作:
          a\:  追加,在当前行后添加一行或多行。添加多行时,除最后一行外,每行末尾都需要用"\"代表未完结
          c\:  行替换,用c后面的字符串替换源数据行,替换多行时,除最后一行外,每行末尾用”\“代表未完结
          i\:   插入,在当前行后插入一行或多行。插入多行时,除最后一行外,每行末尾都需要用"\"代表未完结
          d:   删除指定的行
          p:   打印输出指定的行
          s:   字串替换,用一个字符串替换另一个字符串,格式为"行范围s/旧字串/新字串/g"(类似于vim)。

    2.4.3 行数据操作

      sed '2p' student.txt #查看文件第二行(所有行都输出,第二行多输出了一次)
      sed -n '2p' student.txt #只查看第二行
      sed '2,4d' student.txt #删除第二行到第四行的数据,但不修改文件本身
      sed '2a hello' student.txt #在第二行追加hello
      sed '2i hello \
          world' student.txt #在第二行前插入两行数据
      sed '2c No such person' student.txt #第二行数据被替换
      sed '3s /80/90/g' student.txt #在第三行中,将80替换成99
      sed -i '3s/80/90/g' student.txt #sed操作的数据直接写入文件
      sed -e 's/LIming//g;s/Gao//g' #同时将"Liming"和"Gao"替换为空

三、字符处理命令

  3.1 排序命令 sort

    命令格式:sort [选项] 文件名
      选项:
        -f      忽略大小写
        -n     以数值型进行排序,默认使用字符串型排序
        -r      反向排序
        -t      指定分隔符,默认分隔符是制表符
        -k n[,m]  按照指定的字段范围排序。从第n字段开始,m字段结束(默认到行尾)
    例如:
      sort /etc/passwd #排序用户信息文件
      sort -r /etc/passwd #反向排序
      sort -t ":" -k 3,3 /etc/passwd #指定分隔符":" 用第二字段开头,第三字段结尾排序,就是只用第三字段排序
      sort -n -t ":" -k 3,3 /etc/passwd #使用数值型的第三字段进行排序

  3.2 统计命令wc

    命令格式:wc [选项] 文件名
      选项:
        -i   只统计行数
        -w  只统计单词数
        -m  只统计字符数

四、条件判断

  4.1 按文件类型进行判断

    
测试选项 作用
-b 文件 判断该文件是否存在,并且是否为块设备文件
-c 文件 判断该文件是否存在,并且是否为字符设备文件
-d 文件 判断该文件是否存在,并且是否为目录文件
-e 文件 判断该文件是否存在
-f 文件 判断该文件是否存在,并且是否为普通文件
-L 文件 判断该文件是否存在,并且是否为符号链接文件
-p 文件 判断该文件是否存在,并且是否为管道文件
-s 文件 判断该文件是否存在,并且是否为非空
-S 文件 判断该文件是否存在,并且是否为套接字文件
    两种判断格式
      a)test -e /root/install.log
      b)[ -e /root/install.log ]
      注意:此命令无返回结果,需要用配合$? 判断上一条命令是否执行正确 
      或者使用 [ -d /root ] && echo "yes" || echo "no" #第一个命令执行正确,打印yes,否则打印no

  4.2 按照文件权限判断

    
测试选项 作用
-r 文件 判断文件是否存在,并且是否该文件拥有读权限
-w 文件 判断文件是否存在,并且是否改文件拥有写权限
-x 文件 判断文件是否存在,并且是否改文件拥有执行权限
-u 文件 判断文件是否存在,并且是否改文件拥有SUID权限
-g 文件 判断文件是否存在,并且是否改文件拥有SGID权限
-k 文件 判断文件是否存在,并且是否该文件拥有Sbit权限

  4.3 两个文件之间进行比较

    
测试选项 作用
文件1 -nt 文件2 判断文件1的修改时间是否比文件2的新
文件1 -ot 文件2 判断文件1的修改时间是否比文件2的旧
文件1 -ef 文件2 判断两个文件Inode是否一致,即是否为同一个文件(判断硬链接)
 
    例如:
      ln /root/student.txt /tmp/stu.txt #创建硬链接
      [ /root/student.txt -ef /tmp/stu.txt ] && echo "yes" || echo "no" #判断两个文件是否为同一个

  4.4 两个数值之间比较

    
测试选项 作用
-eq  判断是否相等
-ne 判断是否不相等
-gt 判断是否大于
-lt 判断是否小于
-ge 判断是否大于等于
-le 判断是否小于等于
    例如:
      [ 23 -gt 22 ] && echo "yes" || echo "no" #判断23是否大于22

  4.5 字符串的判断

测试选项 作用
-z 字符串 判断是否为空
-n 字符串 判断是否为非空
字串1 == 字串2 判断是否相等
字串1 != 字串2 判断是否不相等
    例如:
      name=test #赋值变量name
      [ -z "$name" ] && echo "yes" || echo "no" #判断变量是否为空
 
      aa=11
      bb=22
                  #给两个变量赋值
      [ "$aa" == "$bb" ] && echo "yes" || echo "no" #判断这两个变量是否相等

  4.6 多重条件判断

    
测试选项 作用
判断1 -a 判断2 逻辑与,判断1和判断2都为真,结果为真
判断1 -o 判断2 逻辑或,判断1和判断2有一个为真,结果为真
! 判断 逻辑非,原始判断取反
      例如:
      aa=24 #变量赋值
      [ -n "$aa" -a "$aa" -gt 23 ] && echo "yes" || echo "no" # 判断变量不为空且aa大于23是打印yes

五、流程控制

  5.1 if语句

    5.1.1 单分支if条件语句

      if [ 条件判断 ] ;then
        程序
      fi
      或者
      if [ 条件判断 ]
        then
          程序
      fi
      注意:
        a)if语句结尾用fi
        b)[ 条件判断 ]就是test命令判断,中括号和条件判断式之间必须要有空格
        c)then后面跟符合条件之后执行程序。和if同一行时需要加";"号
      例子:判断分区使用率(注意:rate赋值时,等号前后无空格)
        #!/bin/bash
        rate=$(df -h | grep "/dev/sda1" | awk '{print $5}' | cut -d "%" -f 1) #将逻辑分区使用率作为变量赋值给rate
        if [ $rate -ge 80]
          then
            echo "Warning! /dev/sda1 is full !!"
        fi

    5.1.2 双分支if条件语句

      if [ 条件判断式 ]
        then
          条件成立时,执行的程序
        else
          条件不成立时,执行的程序
      fi
      例子1:备份mysql数据库
        #!/bin/bash
        ntpdate asia.pool.ntp.org &> /dev/null #同步系统时间
        date=$(date +%y%m%d) #将当前系统时间按照"年月日格式赋予变量date"
        size=$(du -sh /var/lib/mysql) #统计mysql数据库的大小,并把大小赋予size变量
        if [ -d /tmp/dbbak ]
          then 
            echo "Date:$date!" > /tmp/dbbak/dbinfo.txt
            echo "Date size:$size" >> /tmp/dbbak/dbinfo.txt
            cd /tmp/dbbak
            tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &> /dev/null
            rm -rf /tmp/dbbak/dbinfo.txt
          else
            mkdir /tmp/dbbak
            echo "Date:$date!" > /tmp/dbbak/dbinfo.txt
            echo "Date size:$size" >> /tmp/dbbak/dbinfo.txt
            cd /tmp/dbbak
            tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &> /dev/null
            rm -rf /tmp/dbbak/dbinfo.txt 
      例子2:判断apache是否启动
        #!/bin/bash
        port=$(nmap -sT 192.168.1.10 | grep tcp | grep http | awk '{print $2}')
        #namp命令扫描服务器,截取apache服务的状态,赋予变量port
        if [ "$port" == "open" ]
          then 
            echo "$(date) httpd is ok!!!" >> /tmp/autostart-acc.log
          else
            systemctl start httpd.service &> /dev/null
            echo "$(date) restart httpd!!" >> /tmp/autostart-err.log
        fi 

    5.1.3 多分支if条件语句

      if [ 条件判断式1 ]
        then
          当条件判断式1成立时,执行程序1
        exit 1
      elif [ 条件判断式2]
        then 当条件判断式2成立时,执行程序2
        exit 2
      ......
      else 
        当所有条件都不成立时,最后执行此程序
      fi 

  5.2 case语句

    5.2.1 多分支case条件语句

      case语句和if...elif...else语句一样都是多分支条件语句,不过和if多分支条件语句不同的事
      case只能判断一种条件关系,而if语句可以判断多种条件关系

    5.2.2 格式

      case $变量名 in
        "值1")
          如果变量的值等于值1,则执行程序1
          ;;
        "值2")
          如果变量的值等于值2,则执行程序2
          ;;
        ...
        *)
          如果变量的值都不是以上的值,则执行此程序
          ;;
      esac
      例子:
        #!/bin/bash
        read -p "Please choose yes/no?" -t 30 cho
        case $cho in
          "yes")
            echo "Your choose is yes"
            ;;
          "no")
            echo "Your choose is no"
            ;;
          *)
            echo "Your choose is error"
            ;;
        esac

  5.3 for循环

    5.3.1 语法一

      for 变量 in 值1 值2 值3...
        do 
          程序
        done
      例子1:循环打印1,2,3,4,5

         #!/bin/bash
         for i in 1 2 3 4 5
           do
             echo $i
           done

      例子2:批量解压缩脚本

        cd /lamp

        ls *.tar.gz > ls.log

        for i in $(cat ls.log)

          do 

            tar -zxf $i &>/dev/null

          done

        rm -rf /lamp/ls.log

      5.3.2 语法2

        for ((初始值;循环控制条件;变量变化))

          do

            程序

          done

        例子1:求1到100的和       

          #!/bin/bash
          s=0
          for((i=1;i<=100;i++))
          do
          s=$(($s + i))
          done
          echo "1~100 sum is $s"

        例子2:批量添加指定数量的用户       

          #!/bin/bash
          read -t 30 -p "input name:" name
          read -t 30 -p "input num:" num
          read -t 30 -p "input password:" password

          if [ ! -z "$name" -a ! -z "$num" -a ! -z "$password" ]
            then
            y=$(echo $num | sed 's/[0-9]*$//g')
              if [ -z $y ]
                then
                  for ((i=1;i<=$num;i=i+1))
                    do
                      useradd $name$i &>/dev/null
                      echo $password | passwd --stdin $name$i &>/dev/null
                    done
              fi
          fi

  5.4 while循环与until循环

    5.4.1 while循环

      while循环是不定循环,也称作条件循环。只要条件判断式成立,循环就会一直继续。
      格式:while [ 条件判断式 ]
          do
            程序
          done
      例子:求1~100的和     

      #!/bin/bash

      i=1
      s=0
      while [ $i -le 100 ]
        do
          s=$(($s+$i))
          i=$(($i+1))
        done

      echo "1~100 sum is $s"

    5.4.2 until循环

      until循环,和while循环相反,只要条件判断式不成立则循环,一旦成立,则终止循环。

      格式和while循环一致  

      例子:求1~100的和    

      #!/bin/bash
      i=1
      s=0
      until [ $i -gt 100 ]
        do
          s=$(($s+$i))
          i=$(($i+1))
        done
      echo "1~100 sum is $s"

posted @ 2022-05-14 17:37  flash-bird  阅读(56)  评论(0)    收藏  举报