zoukankan      html  css  js  c++  java
  • shell命令三剑客之grep命令详解

    正则表达式和grep、vim、awk、sed等的关系:
    正则表达式是一种方法,相当于一种工艺,grep等命令相当于是一个具体的加工机器,机器在加工产品的时候,采用这种方法。
    三者的效率:grep>sed>awk

    1. 通配符(globbing)

    常用通配符:

    * 代表 匹配0个或者多个字符 
    ?代表匹配1个字符 
    […] :匹配范围内任意1个字符,例如[az]、[a-z]、[a-z] 
    [^…]: 匹配范围外任意1个字符,表示取反 
    {}:组合匹配,touch a{1,3,5} touch b{1..10}  touch {a,b,c}_{1,2,3} 
    

    例:

    [0-9] 代表数字
    [abcd123]代表取中括号里的任意一个字符
    [a-Z] 代表大小写字母
    [0-Z]代表数字0-9和所有的大小写字母

    正则表达式里通配符和shell里面的通配符的区别:

    • shell里面的通配符:用在bash里面;
    • 正则里面的通配符:用在真正的命令里面。

    2. grep

    grep全称通用正则表达式分析程序(global research regular expression and printing)。

    其实,grep是一个过滤命令,根据特定的正则表达式来过滤文本里的内容。
    grep是根据某个模式进行匹配文件里的一行一行的数据去处理的,如果有匹配的行,就会将整行输出到屏幕上。
    grep用的时候模式要用双引号""引起来!!!

    用途:使用正则表达式搜索文本,并把匹配的行打印出来

    格式:grep [选项] 模式 目标文件

    模式其实就是一个公式,里面有字母+数字+特殊符号,组合成一个正则表达式,表达出某个含义。

    常用选项:

    -v:invert,反转查找,输出与模式不相符的行;
    -An:after-context,同时显示符合条件行的下面n行;
    -Bn:before-context,同时显示符合条件行的上面n行;
    -Cn:同时显示符合条件行的上面n行和下面n行;
    -E:extended regular,支持扩展正则表达式;
    -o:only-matching,仅显示匹配的字符串;
    -f:根据文件内容进行匹配;
    -a:以文本文件方式搜索,不忽略二进制的数据;
    -c:计算找到的符合行的次数;
    -i:ignore-case忽略大小写;
    -n:line-number,顺便输出行号;
    -P  "	"  --》得到Tab键 --》使用perl语言的正则语法,支持	表示table键,s表示空白。
    

    2.1 linux系统支持的三种形式的grep命令

    Linux系统支持三种形式的grep命令,通常将这三种形式的grep命令称为grep命令族,这三种形式具体为:

    1. ls /bin/*grep
    2. fgrep:不支持正则表达式,快速搜索简单模式,按照字符串的字面意思进行匹配吗,相当于grep -F
    3. grep:可以使用基本正则表达式搜索
    4. egrep:可以使用基本和扩展正则表达式搜索,相当于grep -E

    3. 正则表达式

    正则表达式是一个指定文本模式的标准Unix 语法。
    使用特殊元字符实现复杂的搜索问题;
    元字符(meta characters)是用来阐释字符表达式意义的字符,简言之,元字符就是描述字符的字符,它用于对字符表达式的内容、转换及各种操作信息进行描述。

    正则表达式是由一串字符和元字符构成的字符串,简称RE(Regular Expression)。

    基本正则表达式和Unix兼容;
    扩展正则表达式增加了一些新的元字符。

    正则表达式由下列元素构成 :

    • 普通字符,a、b 、1、2
    • 通配符,与文件名通配符不是一回事
    • 修饰符:”*” ”?”等
    • 锚点:以什么开头、以什么结尾。

    正则里的通配符:

    1. “.”:表示一定有一个任意字符
    例:a…b :代表ab之间有三个字符。
    
    1. 方括号表达式:一个文字字符域
    [abc] :a或者b或者c中的一个。
    [^abc] :不是abc其中的一个。
    [0-9]、[a-z]、[A-Z] : 数字、小写、大写。
    
    1. 域表达式和字符类
      考虑到不同的编码方案推荐使用字符类方式(此类方法不常用,以被上面②方式代替!)。
    [:alnum:]    -字母数字混排 等同于[0-Z]
    [:digit:]       -数字  等同于[0-9]
    [:lower:]     -小写字母 等同于[a-z]
    [:upper:]    -大写字母 等同于[A-Z]
    [:space:]     -空白字符,空格、TAB、换行符等
    

    通用修饰符(理解为通配符即可)

    • 问号:表示0个或者1个前面的字符(0或1个)(扩展)
    例:ab?c  代表没有b或者只有一个b,即等同于ac、abc。
    
    • 星号:表示>=0个前面的字符
    例:ab*c 代表没有b或者多个b,即等同于ac、abc、abbc、abbbc......
    
    • +:表示1个或者多个前面的字符(>=1)
    例:ab+c 代表 一个b或者多个b,即等同于abc、abbc、abbc......
    
    • {n}:表示n个前面的字符(前面的字符出现了n次)
    例:ab{2}c 代表b出现了两次,即等同于abbc。
    
    • {n,m}:表示n个到m个前面的字符。
    例:ab{2,4}c 代表2个到4个b,即等同于abbc、abbbc、abbbbc。
    
    • .* :点代表任意一个,星号表示前面的0个或多个,即等同于所有字符。

    锚点搜索

    • “^”:表示以什么开头行
    例 ^aa 代表以aa开头的行。
    
    • 美元符:表示以什么结尾的行
    例 bash$代表以bash结尾的行。
    
    • <:表示词首部。作用等同于
    例 wubing 代表以wubing开头的行。
    
    • >:表示词尾部。作用等同于 
    例 wubing 代表以wubing结尾。 
    
    • < abc >:表示abc这个单词 等价于 abc
    例 <wubing> 代表wubing这个单词。
    

    grep在界定单词的时候,默认使用的分隔符是空白。

    3.1 扩展正则表达式

    egrep、awk和Perl等Linux工具还支持正则表达式扩展出来的一些元字符,这些元字符如下表所示:

    • ?:匹配0个或1个在其之前的那个普通字符
    • +:匹配1个或多个在其之前的那个普通字符
    • ( ):表示一个字符集合
    • | :表示'或',匹配一组可选的字符

    正则表达式分组
    ①“?”、”*”、”+”默认只能修饰前面一个字符
    ②利用圆括号( )可以实现多个字符分组。

    例 f(oo)* :因为oo括起来了,所以把oo看成"一个字符",即f、foo、foooo......
    

    ③在圆括号中利用”|”实现或者的功能

    echo foooeee | egrep --color "(oo|ee){2}"
    echo foooeee | egrep --color "(oo|ee){1}"
    

    转义元字符

    egrep ‘cat.' /etc/aa
    egrep ‘cat.' /etc/aa
    

    正则表达式与通配符匹配的区别:

    • 正则表达式只在少数搜索和替换文本命令中使用;
    • 文件名匹配在bash中匹配文件名;
    • 都使用”*”、”?”但意义不一样;
    • 正则表达式元字符要放在引号内,避免bash Shell解释。

    4. IP的正则

    4.1 ip地址的类别

    简单来讲分为三类:

    • A类网络的IP地址范围为:1.0.0.1-126.255.255.254;
    • B类网络的IP地址范围为:128.1.0.1-191.255.255.254;
    • C类网络的IP地址范围为:192.0.1.1-223.255.255.254

    4.2 ip地址的正则

    写ip地址正则时的方法:需要按个位(1位)、十位(2位)、百位(3位)
    显示文件中的所有A类地址:(1-126)

    "([1-9]|[1-9][0-9]|1[01][0-9]|12[0-6])(.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) ){3}"   
    

    解析:
    先写的个位,十位,百位先写的100-119,再120-126;
    0-255,先0-9,再10-99,100-199,200-249,最后250-255

    显示文件中的所有B类地址:(128-191)

     "(12[89]|1[3-8][0-9]|19[01])(.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) ){3}"
    

    显示文件中的所有C类地址:(192-223)

    "(19[2-9]|2[01][0-9]|22[0-3])(.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) ) {3}"
    

    匹配email地址:

    egrep "[0-Z._]+@[0-Z]+.[a-Z]+"
    

    匹配HTTP URL:

    egrep "^http://([0-Z]+.){2}[a-Z]{2,3}"
    egrep --color "http://(.*..*){2}" --》网址至少有两个点!(适用所有网址)
    

    5. shell中的特殊字符

    • :冒号
      内置的空命令,返回值为0--》while :
    • ;分号
      连续运行命令
    • | 管道
      前面命令的标准输出作为后面命令的标准输入
      正则中表示或者
    • &
      将命令放到后台执行
      表示标准输出和标准错误输出
    • &&
      前面命令执行成功才执行后面的命令
    • ||
      前面命令执行不成功才执行后面的命令
    • 井号
      表示注释
    • ? 问号
      通配符中表示任意1个字符
      正则表达式中表示0个或者1个前面的字符
    • 星号
      通配符中表示0个到多个任意字符
      正则表达式中表示0个或者多个前面的字符
      算术运算中的乘法
    • !惊叹号
      将命令或者条件表达式的返回值取反
      执行历史命令
      vi或者ftp中执行外部shell命令
      间接应用变量 --》${!b}
    • $ 美元符号
      取变量的值
      正则表达式表示行尾
    • 反斜杠
      单字符转义
    • 大于号
      输出重定向
      条件测试中的大于号
    • 小于号
      输入重定向
      条件测试中的小于号
    • = 等号
      变量赋值
      条件测试中的等号
    • 加号
      算术运算中的加号
      正则表达式中1个或多个前面的字符
    • >>
      输出重定向追加
      <<
      here document
    • - 减号
      算术运算中的减号
      命令的选项
      上一次工作目录
      通配符和正则表达式中表示范围[a-z]
      tar -cvf - /home | tar -xvf - 表示输出流或输入流
    • ' ' 单引号
      解决变量赋值空格的问题
      阻止shell替换
    • " " 双引号
      解决变量赋值空格的问题
      阻止shell部分字符替换,对$、!等无效
    • `` 反引号
      命令行替换
    • % 百分号
      算术运算中的模运算
      vi中替换操作中表示所有行
    • () 单圆括号
      子shell中执行命令,会继承父shell的变量
      括起数组元素
    • (()) 双圆括号
      算术运算
      整数比较测试
    • [] 单方括号
      通配符和正则中表示匹配括号中的任意一个字符
      条件测试表达式
      数组中下标括号
    • [[]] 双方括号
      字符串比较测试 --》不能比较小数!比较小数要用bc计算机--》echo "4.5>5.5"|bc ,返回值为0,假的
    • . 句点号
      正则中表示任意1个字符
      当前shell执行脚本命令
      表示当前目录
    • {} 大括号
      通配符扩展 abc{1,2,3}
      正则表达式中表示范围
      匿名函数{cmd1;cmd2;cmd3} &> /dev/null
      括起变量名${abc}a
    • / 正斜杠
      算术运算中的除法
      根目录或路径分割符
    • ^
      在[^abc]通配符中表示取反
      在正则表达式中表示以什么开头

    6. 练习

    1.新建/lianxi目录,复制/etc/passwd到当前目录下。
    2.查找出当前passwd文件中以ftp开头或者mail开头的行,在屏幕输出。
    3.查找出当前passwd文件中首行不是以r、m、f开头的行,在屏幕输出。
    4.查找出当前passwd文件中以bash结尾的行。
    5.查找出/etc/login.defs文件中的有效行(不显示空行和注释行)。
    6.查找出/var/log/messages文档中有16个字母的单词。
    7.查找/etc/passwd文件里用户名包含liu同时使用bash的用户。
    8.查找/etc/ssh/sshd_config文件里的有效行。
    9.查找/etc/ssh/sshd_config文件里的包含连续2个数字的行。
    10.查找出包含特殊字符的行。
    11.查找出不包含数字的行。
    12.查找出/var/log/messages里的ip地址出来。
    13.写一个正则来表示出下面的网址,例如:

    http://www.baidu.com
    http://www.sina.com
    http://www.163.com
    http://www.12306.cn
    http://www.qillu.edu
    

    14.写一个表示邮箱的正则,例如:

    feng@qq.com
    1234feng@163.com
    meng.xianhui@yahoo.cn
    liudenghua@sina.com
    10001@qq.com
    123_ui@12306.com
    qilu@qilu.edu
    

    15.C类ip地址的正则表达式
    section1:范围在192-223之间
    section2和section3和section4范围:0-255之间
    例如:193.168.23.1
    16.监控/var/log/secure文件,统计出ssh错误连接本机次数超过十次的ip地址,拒绝这个ip地址再ssh连接过来(将这个ip地址写入到/etc/hosts.deny黑名单,/etc/hosts.allow是白名单)。

    答案:
    1.新建/lianxi目录,复制/etc/passwd到当前目录下。

    mkdir /lianxi
    cd /lianxi 
    cp /etc/passwd .
    

    2.查找出当前passwd文件中以ftp开头或者mail开头的行,在屏幕输出。

    cat passwd|grep "^ftp|^mail"
    

    3.查找出当前passwd文件中首行不是以r、m、f开头的行,在屏幕输出。

    cat passwd|grep -v "^r|^m|^f"
    

    4.查找出当前passwd文件中以bash结尾的行。

    cat passwd|grep "bash$"
    

    5.查找出/etc/login.defs文件中的有效行(不显示空行和注释行)。

    cat /etc/login.defs|egrep -v "^$|^#"
    

    6.查找出/var/log/messages文档中有16个字母的单词。

    cat /var/log/messages|egrep "<[0-Z]{16}>"
    

    7.查找/etc/passwd文件里用户名包含liu同时使用bash的用户。

    cat passwd|egrep "^[0-Z]*liu[0-Z]*" | egrep "bash" 
    

    cat /etc/passwd|egrep "^.*liu.*:x:"|egrep "bash"
    

    cat passwd|egrep "^[0-Z_]*liu.*bash$"
    

    8.查找/etc/ssh/sshd_config文件里的有效行。

    cat /etc/ssh/sshd_config|egrep -v "^$|^#"
    

    9.查找/etc/ssh/sshd_config文件里的包含连续2个数字的行。

    cat /etc/ssh/sshd_config|egrep "[0-9]{2}"
    

    10.查找出包含特殊字符的行。

    cat /etc/ssh/sshd_config|egrep "[^0-Z]" --》包含特殊字符(^在[]里面,表示取反)
    

    11.查找出不包含数字的行。

    cat /etc/passwd|grep -v ".*[0-9].*"
    

    12.查找出/var/log/messages里的ip地址出来。

    cat /var/log/messages | egrep "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(.([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) ){3}"
    

    13.写一个正则来表示出下面的网址,例如:
    http://www.baidu.com
    http://www.sina.com
    http://www.163.com
    http://www.12306.cn
    http://www.qillu.edu

    [root@liupeng lianxi]# cat dizhi.txt 
    http://www.baidu.com
    http://www.sina.com
    http://www.163.com
    http://www.12306.cn
    http://www.qillu.edu
    [root@liupeng lianxi]# cat dizhi.txt|egrep --color "http://(.*..*){2}"
    http://www.baidu.com
    http://www.sina.com
    http://www.163.com
    http://www.12306.cn
    http://www.qillu.edu
    [root@liupeng lianxi]# 
    

    14.写一个表示邮箱的正则,例如:

    feng@qq.com
    1234feng@163.com
    meng.xianhui@yahoo.cn
    liudenghua@sina.com
    10001@qq.com
    123_ui@12306.com
    qilu@qilu.edu
    

    PS:用户名最大16位。

    [root@liupeng lianxi]# cat youxiang.txt 
    feng@qq.com
    1234feng@163.com
    meng.xianhui@yahoo.cn
    liudenghua@sina.com
    10001@qq.com
    123_ui@12306.com
    qilu@qilu.edu
    [root@liupeng lianxi]# cat youxiang.txt|egrep "[0-Z._]{1,16}+@[0-Z]+.[a-Z]+"
    feng@qq.com
    1234feng@163.com
    meng.xianhui@yahoo.cn
    liudenghua@sina.com
    10001@qq.com
    123_ui@12306.com
    qilu@qilu.edu
    [root@liupeng lianxi]# 
    

    15.C类ip地址的正则表达式
    section1:范围在192-223之间
    section2和section3和section4范围:0-255之间
    例如:193.168.23.1

    [root@liupeng lianxi]# cat ipip.txt 
    193.168.23.1
    10.10.10.1
    192.168.12.12
    123.123.123.123
    [root@liupeng lianxi]# cat ipip.txt|egrep "(19[2-9]|2[01][0-9]|22[0-3])(.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}"
    193.168.23.1
    192.168.12.12
    [root@liupeng lianxi]# 
    

    16.监控/var/log/secure文件,统计出ssh错误连接本机次数超过十次的ip地址,拒绝这个ip地址再ssh连接过来(将这个ip地址写入到/etc/hosts.deny黑名单,/etc/hosts.allow是白名单)。

    #!/bin/bash
    while true
    do
            cat secure|egrep "Failed passwd"|egrep -o "192(.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}"|sort|uniq -c|sort -nr >secure.txt
            deny=$(cat /etc/hosts.deny|egrep "^sshd:192(.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$"|awk -F: '{print $2}')
            echo $deny >deny_ip.txt
            cat secure.txt|while read times IP
            do
                    if (( $times>=2 ))
                    then
                            if ! grep $IP deny_ip.txt &>/dev/null
                            then
                                    echo "sshd:$IP" >>/etc/hosts.deny&&echo "$IP has been written to /etc/hosts.deny"
                            fi
                    fi
            done
    sleep 1
    done
    

  • 相关阅读:
    CF1202F You Are Given Some Letters...
    CF1178E Archaeology
    PTA (Advanced Level) 1005 Spell It Right
    PTA (Advanced Level) 1004 Counting Leaves
    Qt5——从零开始的Hello World教程(Qt Creator)
    PTA (Advanced Level) 1003 Emergency
    PTA (Advanced Level) 1002 A+B for Polynomials
    HDU 1272 小希的迷宫
    FZU 2150 Fire Game
    HihoCoder
  • 原文地址:https://www.cnblogs.com/lpeng94/p/12685249.html
Copyright © 2011-2022 走看看