正则表达式与grep
(前半部分为理解概念,后面是应用实例)
什么是正则表达式:
正则表达式:Regular Expression, REGEX
是由一类特殊字符及文本字符所编写的模式,其有些字符不表示其字面意义,而是用于表示控制或通配的功能;
什么是grep:
grep: Global search REgular expression and Print out the line.Gloal search REGEX
文本搜索工具,根据用户指定的“模式(pattern)”对目标文本进行过滤,显示被模式匹配到的行 grep: Global search REgular expression and Print out the line. 文本搜索工具,根据用户指定的“模式(pattern)”对目标文本进行过滤,显示被模式匹配到的行.
Linux上文本处理三剑客:
grep:egrep, fgrep:文本搜索工具;基于”pattern“对给定文本进行搜索操作;
sed:Stream EDitor,流编辑器,行编辑工具;文本编辑工具;
awk:GNU awk,文本格式化工具;文本报告生成器;
正则表达式只是字符串的一种描述,只有和支持正则表达式的工具相结合才能进行字符串处理。(grep)
所以主要理解学习grep的正则表达式:
grep命令:
作用:文本搜索工具,根据用户指定的”pattern(过滤条件)“对目标文本逐行进行匹配检查;打印出符合条件的行;
模式:由文本字符及正则表达式元字符所编写的过滤条件;
grep [OPTIONS] PATTERN [FILE...]
常用选项:
--color=auto:对匹配到的文本着色后高亮显示;
-i:忽略字符大小写;
-o:仅显示匹配 到的文本自身;
-v, --invert-match:反向匹配;
-E:支持扩展的正则表达式;
-q, --quiet, --silient:静默模式,不输出任何信息;
eg: ]#grep root /etc/passwd
基本正则表达式元字符:
(1)字符匹配:
.:匹配任意单个字符;
[ ]:匹配范围内的任意单个字符;
[^ ]:匹配范围外的任意单个字符;
[:digit:],[:lower:], [:upper:], [:alpha:], [:alnum:], [:space:], [:blank:], [:punct:]
(2)匹配次数
用在要指定其出现的次数的字符后面,用限制其前面的字符要出现的次数默认工作于贪婪模式
*:匹配前面的字符任意次(0,1或多次);
grep "x*y":
xxxyabc
yabc
abcxy
abcy
.*:任意长度的任意字符;
\+:匹配前面的字符至少1次;
grep "x\+y":
xxxyabc
yabc
abcxy
abcy
\?:匹配前面的0次或1次,即前面的字符可有可无;
grep "x\?y":
xxxyabc
yabc
abcxy
abcy
\{m\}:其前面的字符出现m次,m为非负整数;
grep "x\{2\}y":
xxxyabc
yabc
abcxy
abcy
\{m,n\}:其前面的字符出现m次,m为非负整数;[m,n]
\{0,n\}:至多n次;
\{m,\}:至少m次;
(3)位置锚定
限制使用模式搜索文本,限制模式所匹配到的文本只能出现于目标文本的哪个位置;
^:行首锚定;用于模式的最左侧,^PATTERN
$:行尾锚定;用于模式的最右侧,PATTERN$
^PATTERN$:要让PATTERN完全匹配一整行;
^$:空行;
^[[:space:]]*$:
单词:由非特殊字符组成的连续字符(字符串)都称为单词;
\<或\b:词首锚定,用于单词模式的左侧,格式为\<PATTERN, \bPATTERN
\>或\b:词尾锚定,用于单词模式的右侧,格式为PATTERN\>, PATTERN\b
\<PATTERN\>:单词锚定;
(4)分组与引用:
\(PATTERN\):将此PATTERN匹配到的字符当作一个不可侵害整体进行处理;
Note:分组括号中的模式匹配到的字符会被正则表达式引擎自动记录于内部的变量中,这些变量是\1, \2, \3, ...
pat1\(pat2\)pat3\(pat4\(pat5\)pat6\)
\n:模式中第n个左括号以及与之匹配的右括号之间的模式所匹配到的字符串;(不是模式,而是模式匹配的结果)
\1:第一组括号中的pattern匹配到的字符串;
\2:第二组括号中的pattern匹配到的字符串;
通过一组练习来更深入的了解grep元字符:
1、显示/etc/passwd文件中不以bash结尾的行;
[[email protected] ~]# grep -v "bash$" /etc/passwd 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
注:-v的使用,[OPTION]的灵活掌握
2、找出/etc/passwd文件中的三位或四位数;
[[email protected] ~]# grep "\<[0-9]\{3,4\}\>" /etc/passwd games:x:12:100:games:/usr/games:/sbin/nologin avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin polkitd:x:999:998:User for polkitd:/:/sbin/nologin abrt:x:173:173::/etc/abrt:/sbin/nologin colord:x:998:996:User for colord:/var/lib/colord:/sbin/nologin
注: 需要注意的是三四位数字需要词首尾锚定
3、找出/etc/grub2.cfg文件中,以至少一个空白字符开头,后面又跟了非空白字符的行;
[[email protected] ~]# grep "^[[:space:]]\+[^[:space:]]" /etc/grub2.cfg load_env set default="${next_entry}" set next_entry= save_env next_entry set boot_once=true set default="${saved_entry}" menuentry_id_option="--id" menuentry_id_option=""
注:^符号的使用,第一个^是锚定行首的意思,第二个^表示“非”
4、找出"netstat -tan”命令的结果中,以‘LISTEN’后跟0个或多个空白字符结尾的行;
[[email protected] ~]# netstat -tan Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:6011 0.0.0.0:* LISTEN tcp 0 0 172.18.250.58:22 172.18.46.1:58743 ESTABLISHED tcp 0 52 172.18.250.58:22 172.18.46.1:61570 ESTABLISHED tcp6 0 0 :::22 :::* LISTEN tcp6 0 0 ::1:25 :::* LISTEN tcp6 0 0 ::1:6010 :::* LISTEN tcp6 0 0 ::1:6011 :::* LISTEN
#netstat -tan命令的执行结果,通过管道再次处理
[[email protected] ~]# netstat -tan | grep "LISTEN\[[:space:]]*$" grep: 字符类的语法是 [[:space:]],而非 [:space:] [[email protected] ~]# netstat -tan | grep "LISTEN[[:space:]]*$" tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN tcp6 0 0 :::22 :::* LISTEN tcp6 0 0 ::1:25 :::* LISTEN tcp6 0 0 ::1:6010 :::* LISTEN
注:$行尾锚定
5、找出"fdisk -l“命令的结果中,包含以/dev/后跟sd或hd及一个小字母的行;
[[email protected] ~]# fdisk -l |grep "/dev/[sh]d[a-z]\>" 磁盘 /dev/sda:128.8 GB, 128849018880 字节,251658240 个扇区 [[email protected] ~]#
注:[sh]的表示方式,还可以:egrep……(s|h),结果如下:(完全一致)
[[email protected] ~]# fdisk -l |egrep "/dev/(s|h)d[a-z]\>" 磁盘 /dev/sda:128.8 GB, 128849018880 字节,251658240 个扇区 [[email protected] ~]#
6、找出”ldd /usr/bin/cat“命令的结果中 文件路径;
#ldd /usr/bin/cat | egrep "/.*"
[[email protected] ~]# ldd /usr/bin/cat | egrep "/.*" libc.so.6 => /lib64/libc.so.6 (0x00007f659ae51000) /lib64/ld-linux-x86-64.so.2 (0x00007f659b227000) [[email protected] ~]# ldd /usr/bin/cat | egrep "/[^[:space:]]+" libc.so.6 => /lib64/libc.so.6 (0x00007fabf6fe7000) /lib64/ld-linux-x86-64.so.2 (0x00007fabf73bd000) [[email protected] ~]# ldd /usr/bin/cat | egrep -o "/[^[:space:]]+" /lib64/libc.so.6 /lib64/ld-linux-x86-64.so.2
注:前两次的错误,在于考虑不周全,"."号后面有可能有其它的数据如上;路径要非空;第二次错误在于-O的选项使用,只显示查找到的文本本身,不显示其它信息
7、找出/proc/meminfo文件中,所有以大写或小写s开头的行;至少用三种方式实现;
[[email protected] ~]# egrep "^[sS].*" /proc/meminfo SwapCached: 0 kB SwapTotal: 2097148 kB SwapFree: 2097148 kB Shmem: 6852 kB Slab: 76524 kB SReclaimable: 40696 kB SUnreclaim: 35828 kB
注:[sS],(s|S),-i S;三种方式的灵活使用
8、显示当前系统上root、centos或slackware用户的相关信息;
[[email protected] ~]# egrep "^(root|centos|slackware)" /etc/passwd root:x:0:0:root:/root:/bin/bash slackware:x:1002:1002::/home/slackware:/bin/bash
由于当前主机没有centos用户,可以先添加上用户,再测试,结果如下:
[[email protected] ~]# useradd centos [[email protected] ~]# egrep "^(root|centos|slackware)" /etc/passwd root:x:0:0:root:/root:/bin/bash slackware:x:1002:1002::/home/slackware:/bin/bash centos:x:1226:1228::/home/centos:/bin/bash
9、echo输出一个绝对路径,使用egrep取出其基名;
[[email protected] ~]# echo /etc/passwd | egrep "^/[0-9a-z]+[^[:space:]]+/?$" /etc/passwd [[email protected] ~]# echo /etc/passwd | egrep "[^/][0-9a-z]+[^[:space:]]+/?$" /etc/passwd [[email protected] ~]# echo /etc/passwd | egrep "[^/]+/?$" /etc/passwd [[email protected] ~]# echo /etc/passwd | egrep -o "[^/]+/?$" passwd
注:做错了好几次,受到第6题影响,想多了,明白“非”“/”但是表示错误
10、找出ifconfig命令结果中的1-255之间的整数;
[[email protected] ~]# ifconfig | egrep "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) > ^C [[email protected] ~]# ifconfig | egrep "([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]) > ^C [[email protected] ~]# ifconfig | egrep "([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.18.250.58 netmask 255.255.0.0 broadcast 172.18.255.255 inet6 fe80::20c:29ff:fe53:9db prefixlen 64 scopeid 0x20<link> ether 00:0c:29:53:09:db txqueuelen 1000 (Ethernet) RX packets 679699 bytes 75217163 (71.7 MiB) TX packets 17320 bytes 2036768 (1.9 MiB) lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> RX packets 403 bytes 90540 (88.4 KiB) TX packets 403 bytes 90540 (88.4 KiB) [[email protected] ~]# ifconfig | egrep "\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>" inet 172.18.250.58 netmask 255.255.0.0 broadcast 172.18.255.255 inet6 fe80::20c:29ff:fe53:9db prefixlen 64 scopeid 0x20<link> ether 00:0c:29:53:09:db txqueuelen 1000 (Ethernet) RX packets 679835 bytes 75230524 (71.7 MiB) TX packets 17429 bytes 2050446 (1.9 MiB) lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
注:此题花费挺长时间,主要是不明白1-255字符的表示方法,难得的是上面的代码终于还是码出来了,后来还是范了两个错误,第一个是最后少了一个“,第二个是没有做词首词尾的锚定,导致撮数据不准确
11、添加用户bash、testbash、basher及nologin,要求前三个用户的默认shell为/bin/bash,nologin的默认shell为/sbin/nologin,而后找出其用户名与shell名相同的用户;
[[email protected] ~]# useradd -s bash /bin/bash [[email protected] ~]# useradd -s testbash /bin/bash [[email protected] ~]# useradd -s basher /bin/bash [[email protected] ~]# useradd -s nologin /sbin/nologin
[[email protected] ~]# egrep "^([0-9a-z]+:)\1$" ^C [[email protected] ~]# egrep "^([0-9a-z]+:)\1$" /etc/passwd [[email protected] ~]# egrep "(^[0-9a-z]+:)\1$" /etc/passwd [[email protected] ~]# egrep "(^[0-9a-z]+\>:)\1$" /etc/passwd [[email protected] ~]# egrep "(^[0-9a-z]+\>:).*\1$" /etc/passwd [[email protected] ~]# egrep "(^[0-9a-z]+\>).*\1$" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt bash:x:1222:1224::/home/bash:/bin/bash nologin:x:1225:1227::/home/nologin:/sbin/nologin
还是出错了好几次,有思路,但是还是不周全,用乱了,首先没有做词尾锚定,用+号是对的一个或是多个字符,后面我想用“:”来分隔开,其实用不着分隔,再就是“.* ”表示中间有很多不限的字符。最后一个"$"符号,用来表示以\1行尾锚定。