grep-egrep-fgrep家族

Shell Liemer_Lius 1068℃ 0评论

系统帮助:

grep, egrep, fgrep - print lines matching a pattern
grep: Global Research Regular Expression, 根据模式搜索文本,并将符合模式的文本行显示出来。
Pattern: 模式, 文本字符和正则表达式的元字符组合而成匹配条件

模式中,如果没有元字符,可以不用引号(单双)括起来。
正则表达式的元字符? 详见下面.

grep的格式: 使用基本正则表达式定义的模式来过滤文本的命令;
grep [options] PATTERN [FILE...]
 
grep:使用基本正则表达式定义的模式来过滤文本的命令;
 -i: 忽略大小写
 -v: 取反, 显示没有被模式匹配到的行
 -o: 仅显示匹配的字符串, 每个字符串显示为一行,用于寻找匹配次数,与wc可以一起用。
 --color|--colour: 高亮颜色显示匹配的字符串.
 -E: 使用扩展正则表达式
 -A #: After, #指定显示的行数, 表示匹配到行以后, 一并显示其后面的两行; 各匹配结果之间, 以"--"上下分割; 注: 必须要指定行数#
 -B #: Before, 一并显示其前的#行.
 -C #: Context, 一并显示上下#行.

Exp:

 # grep 'root' /etc/passwd
 root:x:0:0:Liemer,Beijing,110,119:/root:/bin/bash
 operator:x:11:0:operator:/root:/sbin/nologin

grep中用到的引号, 只要不涉及变量, 单双引号都是可以的; 如果不涉及元字符, 引号甚至是可以省略的.

shell中的特殊字符的含义: (注意,与元字符的含义不同)
 *: 任意长度的任意字符
 ?: 任意单个字符
 []: 指定范围内
 [^]: 指定范围外

正则表达式:REGular EXPression, REGEXP

元字符:表示通配或更加复杂意义功能的字符. 元字符仅修饰其前字符.
1. .: 匹配任意单个字符
 # grep 'r..t' /etc/passwd
 root:x:0:0:Liemer,Beijing,110,119:/root:/bin/bash
 operator:x:11:0:operator:/root:/sbin/nologin
 ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

2. []: 匹配指定范围内的任意单个字符(和bash一样)

3. [^]:匹配指定范围外的任意单个字符(和bash一样)
 字符集合:[:digit:], [:lower:], [:upper:], [:punct:], [:space:], [:alpha:], [:alnum:]
 表示: 数字, 小写字母, 大写字母, 标点, 空白字符, 所有大小写字母, 大小写字母和数字.
 上面的只是字符集合, 实际运用中, 还需要在外层包裹一个中括号[].
 # grep '[[:alnum:]]$' b.txt //过滤以大小写字母和数字结尾的行
 # grep '[[:space:]][[:alnum:]]$' b.txt //过滤以一个空白字符紧跟一个大小写字母或数字结尾的行.
 
4. 表示匹配次数(贪婪模式: 默认的正则表达式的匹配模式, 尽量最长地匹配):
 *: 匹配其前面的字符任意次,这里就与shell中表示的的意思不一样了
 .*: 任意长度的任意字符

5. \?: 匹配其前字符0次或者1次,同样需要转义,bash中的?表示任意单个字符
 
6. \{m,n\}: 匹配其前面的字符至少m次,至多n次; 转义是防止shell解释{}为命令行展开(# touch ~/{a,b}.txt; $ ls ~ --> a.txt b.txt);
 \{1,\}: 至少一次, 多了不限.
 \{0,3\}: 最多三次, 少了不限.
 \: 转义字符的意思, 就是防止按照shell的格式来解释相关的字符, 而是用正则的方法来实现.

例子:

Exp: 新建文本, 输入如下内容, 一段字符串一行.
 a, b, ab, aab, acb, adb, amnb

1)匹配a任意次, 后面跟一个b的字符串:
 a*b: a出现任意次, 后面跟一个b;
 # grep 'a*b' a.txt
 b
 ab
 aab
 acb
 adb
 amnb

2)匹配a可有可无, 后面跟一个b的字符串: a?b: a出现1次或者0次. 注: 要用\来转意.
 # grep 'a\?b' a.txt
 b
 ab
 aab
 acb
 adb
 amnb

3)匹配a开头, b结尾, 中间任意长度任意字符的字符串. a.*b: 贪婪匹配, a开头, b结尾, 中间任意字符.
 # grep 'a.*b' a.txt
 ab
 aab
 acb
 adb
 amnb

4)匹配a至少一次, 至多三次, 后面跟一个b的行:
 # grep 'a\{1,3\}b' a.txt
 ab
 aab
 
 5)统计/etc/inittab中空白行的数量.
 # grep '^$' /etc/inittab |wc -l
 5

7. 位置锚定:

^: 锚定行首,此字符后面的任意内容必须出现在行首
 $: 锚定行尾,此字符前面的任意内容必须出现在行尾
 ^$: 空白行
 
 Exp:
 1)行首锚定.
 # grep '^r..t' /etc/passwd
 root:x:0:0:Liemer,Beijing,110,119:/root:/bin/bash
 
 2)行尾锚定.
 # grep '/bin/bash$' /etc/passwd
 root:x:0:0:Liemer,Beijing,110,119:/root:/bin/bash
 cactiuser:x:505:505::/home/cactiuser:/bin/bash
 lius:x:506:506::/home/lius:/bin/bash
 apache:x:498:498::/home/apache:/bin/bash
 openstack:x:509:509::/home/openstack:/bin/bash
 hive:x:5000:5000:Hive:/home/hive:/bin/bash

8. 单词锚定

\<或\b: 锚定词首,其后面的任意字符必须作为单词首部出现
 \>或\b: 锚定词尾,其前面的任意字符必须作为单词的尾部出现
 # grep '\<root' /etc/passwd //过滤root作为词首的行
 # grep 'root\>' /etc/passwd //过滤root作为词尾的行
 # grep '\<root\>' /etc/passwd //过滤含有root单词的行,必须是单词。

Exp: 编写文档:
 This is root.
 The user is mroot.
 rooter is a dog's name.
 chroot is a command.
 mrooter is not a word.

1) 查找以root做为词尾的行.
 [root@lius]<~># grep 'root\>' a.txt 或 grep 'root\b' a.txt
 This is root.
 The user is mroot.
 chroot is a command.
 2) 查找以root做为词首的行.
 [root@lius]<~># grep '\<root' a.txt 或 grep '\broot' a.txt
 This is root.
 rooter is a dog's name.
 3) 查找含有root单词的行.
 [root@lius]<~># grep '\broot\b' a.txt 
 This is root.
 [root@lius]<~># grep '\<root\>' a.txt

9. 分组:

\(\): 分组, 将()里面的内容当做一个整体来处理.
 分组的意义: 分组一般用于引用, 即: 后向引用.
 \(ab\)*: 匹配ab出现任意次的字符串.
 后向引用: 即分组后的内容, 后面一般会有相应的元字符对其进行引用.
 \1: 引用第一个左括号以及与之对应的右括号所包括的所有内容(注意:括号是可以嵌套的)
 \2: 引用第二个左括号以及与之对应的右括号所包括的所有内容
 \3: 引用第三个左括号以及与之对应的右括号所包括的所有内容

Exp:过滤一行中, 前面有一个单次, 后面也有包含这个单词内容的行.
 He love his lover.
 She like her liker.
 He like his lover.
 she love her liker.

1)匹配前面一段代码, 后面出现相同一段代码的行.
 # grep 'l..e.*l..e' a.txt
 He love his lover.
 She like her liker.
 He like his lover.
 she love her liker.
 可见, 上面的匹配格式, 不能满足我们的需求.

后向引用:
 # grep '\(l..e\).*\1' a.txt //l..e可以匹配love和like, \1表示引用的变量编号.
 He love his lover.
 She like her liker.
 后面出现前面第一个括号里面的内容的行, 才能过滤出.

2)引用多个变量呢? 文本中添加一行:
 she loves her liker. He loves his liker.
 引用两个变量:
 # grep '\(l.v\).*\(l.k\).*\1.*\2' a.txt
 she loves her liker. He loves his liker.
 这里有颜色显示的部分是: loves her liker. He loves his lik, 引用的结果是准确的.
 
 3)过滤/etc/inittab中, 出现一个数字, 中间任意字符, 但以这个数字结尾的行:
 # grep '\([[:digit:]]\).*\1' /etc/inittab

练习题:

1、显示/proc/meminfo文件中以不区分大小的s开头的行;
 grep -i '^s' /proc/meminfo
 grep '^[sS]' /proc/meminfo
 
 2、显示/etc/passwd中以nologin结尾的行; 
 grep 'nologin$' /etc/passwd

取出默认shell为/sbin/nologin的用户列表
 grep "nologin$' /etc/passwd | cut -d: -f1

取出默认shell为bash,且其用户ID号最小的用户的用户名
 grep 'bash$' /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1

3、显示/etc/inittab中以#开头,且后面跟一个或多个空白字符,而后又跟了任意非空白字符的行;
 grep "^#[[:space:]]\{1,\}[^[:space:]]" /etc/inittab

4、显示/etc/inittab中包含了:一个数字:(即两个冒号中间一个数字)的行;
 grep ':[0-9]:' /etc/inittab

5、显示/boot/grub/grub.conf文件中以一个或多个空白字符开头的行;
 grep '^[[:space:]]\{1,\}' /boot/grub/grub.conf

6、显示/etc/inittab文件中以一个数字开头并以一个与开头数字相同的数字结尾的行;
 grep '^\([0-9]\).*\1$' /etc/inittab

7、找出某文件中的,1位数,或2位数;
 grep '[0-9]\{1,2\}' /proc/cpuinfo
 grep --color '\<[0-9]\{1,2\}\>' /proc/cpuinfo

8、找出ifconfig命令结果中的1-255之间的整数;


 9、查找当前系统上名字为student(必须出现在行首)的用户的帐号的相关信息, 文件为/etc/passwd
 grep '^student\>' /etc/passwd | cut -d: -f3
 id -u student

student1
 student2

10、分析/etc/inittab文件中如下文本中前两行的特征(每一行中出现在数字必须相同),请写出可以精确找到类似两行的模式:
 l1:1:wait:/etc/rc.d/rc 1
 l3:3:wait:/etc/rc.d/rc 3
 grep '^l\([0-9]\):\1.*\1$' /etc/inittab

正则表达式:REGEXP, REGular EXPression,分为基本正则表达式(Basic)和扩展正则表达式(Extended)

grep的扩展正则表达式: 不用脱义\
 grep -E = egrep 
 字符匹配:以下三种, 扩展和基本用法相同, 没有需要脱义的符号.
 .:任意单个字符
 []:范围内的任意单个字符
 [^]:范围外的任意单个字符

次数匹配中:?|{}不用再脱义, 另外多了一个+. 
 *: 其前自
 ?: 其前字符0次或者1次.
 +: 匹配其前面的字符至少1次, 相当于\{1,\}
 {m,n}: 指定范围, 不用再脱义.

位置锚定:和非扩展的用法完全相同
 ^: 行首
 $:行尾
 \<, \b:词首
 \>, \b:词尾


 分组:用法不同, ()不再用脱义
 ():分组
 \1, \2, \3, ...

同时, 还扩展了一个字符|, 表示或者.
 |: or, 或者.
 C|cat: 不是指Cat或cat, 而是C或cat; 也就是说, |左右的两个字段是或者的关系, 而不是只匹配左右的前后两个字符.
 如果要表示前者的意思, 分组就显现出作用了, 应该是(C|c)at.

扩展示例:

1)找出/boot/grub/grub.conf文件中1-255之间的数字;
 egrep --color \<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\> /boot/grub/grub.conf
 egrep --color '\<[0-9]\>|\<[1-9][0-9]\>|\<1[0-9][0-9]\>|\<2[0-4][0-9]\>|\<25[0-5]\>' /boot/grub/grub.conf
 这里, 用括号分组, 则锚定词首词尾的时候是将一个整体全部锚定; 如果不加括号, 则|符号之后的并不能锚定, 大于255的数值也会被过滤出来.

2)ifconfig -a的内容, 保存到c.txt中, 过滤ip地址类的行.
 注: \. --> 对 "." 进行脱义, 非元字符., 可以代表任意一个字符, 如可以过滤出192*168.213.55

ifconfig -a > c.txt
 egrep --color '\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>' c.txt

这里, 必须对([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])进行分组, 否则过滤的数字会超出范围.


 ifconfig | egrep '\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>'

ifconfig | egrep --color '(\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.){3}\<([0-9]|[1-9][0-9]|1[0-9][0-9] |2[0-4][0-9]|25[0-5])\>'

IPV4的分类:

IPv4: 一共5分类, 以首位的区间为分类标准.
 5类:A B C D E, 有用的只有三类.
 A:1-127
 B:128-191
 C:192-223

IP地址的过滤规则:第一位的范围【1-223】,每一位的最大值不能是255,
 \<([1-9]|[1-9][0-9]|1[0-9]{2}|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-4])\>){2}\.\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4])\>

马哥的博客:http://mageedu.blog.51cto.com/

grep, egrep:默认的grep是非常浪费cpu的时钟周期的。
fgrep: fast grep, 任何正则表达式的字符, 都当做普通字符来显示. 不支持正则表达式, 所以执行速度快. 
 # echo -e "r..t\nroot" > a.txt
 # grep 'r..t' a.txt
 r..t
 root
 # fgrep --color 'r..t' a.txt
 r..t

 

转载请注明:liutianfeng.com » grep-egrep-fgrep家族

喜欢 (0)

发表回复