一、正则表达式
正则表达式 (regular expression),简写(regex),用来描述一些表达复杂模式的方法。
linux中的grep, vi, find, sed等命令都支持正则表达式。
linux@myccloves:~$ grep '^VER' /etc/os-release
VERSION_ID="15.6"
VERSION="15.6"
正则表达式用特殊字符组成,称为元字符(metacharacters)。^表示以……开始,正则表达式应该放到单引号中防止和shell解释时的冲突。
linux@myccloves:~$ cat /etc/os-release | egrep '[ew]{2}'
PRETTY_NAME="Deepin 15"
NAME="Deepin"
ID=deepin
HOME_URL="https://www.deepin.org/"
BUG_REPORT_URL="http://feedback.deepin.org/feedback/"
此例中[ew]表示匹配e或w中的1个,而后面的{2}表示重复两次,也就是说有ee或ww字样的就符合要求。
我们要注意fgrep不支持正则,而grep支持简单的正则,egrep支持扩展正则表达式。
二、正则表达式的组成
一个正则表达式可由下列元素构成:
- 文字字符 比如:字母,数字等
- 通配符 比如:"." 表示匹配任意字符
- 修饰符 可以改变它前面离它最近的模式字符的含义。如:ab*c,匹配ac,abc,abbc,abbbc等,*表示重复0次或多次
- 锚点 指定模板的上下文,比如一行的开始,或一个字的结束。比如:^cat 表示以cat开头。
三、括号表达式
表达式 | 说明 |
---|---|
[aeiou] | 表示匹配其中的一个字符 |
[^aeiou] | 表示匹配非aeiou的一个字符 |
[a-d] | 表示匹配a,b,c,d其中的一个 |
[A-Z] | 表示匹配所有大写字母 |
[0-9] | 表示匹配数字 |
[:alnum:] | 表示匹配字母,数字 |
[:alpha:] | 表示匹配字母 |
[:blank:] | 表示匹配空格和制表符 |
[:digit:] | 表示匹配数字 |
[:lower:] | 表示匹配小写字母 |
[:space:] | 表示匹配空白 |
[:upper:] | 表示区大写字母 |
比如:匹配有大写字母的行
linux@myccloves:/etc$ cat resolv.conf
# Generated by NetworkManager
nameserver 172.16.18.1
linux@myccloves:/etc$ cat resolv.conf | egrep '[[:upper:]]'
# Generated by NetworkManager
四、通用修饰符
表达式 | 说明 |
---|---|
? | 表示重复0次或1次 |
* | 表示重复0次或多次 |
+ | 表示重启1次或多次 |
{m} | 表示重复m次 |
{m,n} | 表示重复m-n次 |
注意:修饰符都很贪婪,如:对于now is the time, t.*e匹配the time而不是the,这就是贪婪!
五、描点搜索
表达式 | 说明 |
---|---|
^foo | 表示以foo开头的行 |
foo$ | 表示以foo结尾的行 |
<foo> | 表示字首和字尾, 为了与普通字符<>区分,则用<, > |
六、正则表达式分组
对于 ?, *, +重复前面的字符,如果想重复前面的多个字符可以分组。比如: foo(bar)? 重复bar零次或1次。
用()进行分组,多个字符串可以用|分隔。(foo|foobar)表示匹配foo或foobar
七、转义元字符
正则的元字符具有特殊的意义,如果想把它变成普通字符可以用进行转议。比如 "." 表示匹配任意字符,但就想把点当成普通字符点,可以这样:.
总结:
字符 | 功能 | 语法 | 说明 |
---|---|---|---|
. | 通配符 | 基本 | 表示匹配一个或任意字符 |
[abc],[a-z] | 包含域 | 基本 | 表示域内任意一个字符 |
[abc],[a-z] | 排除范围 | 基本 | 表示不包含在域内的任意一个字符 |
? | 修饰符 | 扩展 | 表示0或者1个前面的项 |
* | 修饰符 | 基本 | 表示0或者多个前面的项 |
+ | 修饰符 | 扩展 | 表示1或者多个前面的项 |
{m,n} | 修饰符 | 扩展 | 表示前面的项重复m-n |
{n} | 修饰符 | 基本 | 表示前面的项重得n次 |
^ | 锚 | 基本 | 表示一行的开始 |
$ | 锚 | 基本 | 表示一行的结束 |
< | 锚 | 基本 | 表示一个单词的开始 |
> | 锚 | 基本 | 表示一个单词的结束 |
(...) | 分组 | 基本 | 修饰一组字符 |
(...|...) | 分组 | 扩展 | 允许指定可选模式 |
转义 | 扩展(基本) | 转义元字符 |
注意 :正则表达式与文件名匹配是不同的,意义也不同。所以正则要用''括起来。
八、sort命令
sort命令用于排序,他的选项有:
-b 忽略一行开始的空格符或者制表符
-g 排浮点数排序
-n 按整数排序
-r 降序
-k 指定序列
-t 指定分隔符
sort命令,之前我们接触过,默认按字母顺序排序。可以按数字排序,可以进行升序、降序等。 除此之外,sort可以按字段排序,我们分析一下:
数据如下:姓名,语文,数学
张三 98.5 97
李四 82.35 85.5
王五 100 99.5
马六 94.5 80
sort默认按姓名排序,如果现在想要按语文(第二列)排序,而且是降序怎么办法? 已知各个数据之间用水平制表符分隔的:
linux@myccloves:~/test$ sort -k2 -g -r 1.txt
王五 100 99.5
张三 98.5 97
马六 94.5 80
李四 82.35 85.5
-k 表示按指定列数排序,这里指定的是2。
-g 表示按小数排序。
-r 表示降序。
我们也可以多列排序:
张三 男 98.5 97
李四 男 82.35 85.5
王五 男 100 99.5
王冰 女 94.5 80
先按性别排序,再按语文成绩降序排序:
linux@myccloves:~/test$ sort -k2,2 -k3gr,3 2.txt
王冰 女 94.5 80
王五 男 100 99.5
张三 男 98.5 97
李四 男 82.35 85.5
-k2,2 表示按第二列排序,后面的2表示到第二列止,如果不指定,则从第二列开始一直到行尾为作关键字。
-k3gr,3 表示按第三列,小数降序排列。
指定分隔符排序,比如:/etc/passwd文件,我想按uid降序排序(第三列):
sort -t: -k3rn /etc/passwd
-t:指定分隔符为 ":"
-k3rn表示第三列,降序,按整数排序。
例:对ps aux按占用内存的大小进行排序
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 219240 7796 ? Ss 09:42 0:02 /sbin/init splash
root 2 0.0 0.0 0 0 ? S 09:42 0:00 [kthreadd]
发现内存占用百分比是第4列:
ps aux | sort -k4nr
如果你运行了,你会发现,标题在里面了,所以我们 ps aux时把标题去掉。 去掉的方法用tail -n +2,这条命令要注意:
- tail -n 2 表示显示后两条
- tail -n +2 表示从第二行开始读取
所以我们先用tail -n +2过滤掉标题,之后再用管道符流向 sort程序:
ps aux | tail -n +2 | sort -k4nr
九、uniq命令
uniq可以删除重复记录,一般需要和sort组合。
linux@myccloves:~/test$ cat 1.txt
0
1
0
0
0
2
linux@myccloves:~/test$ cat 1.txt | uniq -c
1 0
1 1
3 0
1 2
我们发现有:4个0是重复的,1,2没有重复。 通过 uniq -c得到的结果是:0重复1次,1重复1次,0重复3次,2重复1次,这里的-c显示重复几次。
但我们0明明是重复4次啊,这说明uniq统计紧挨着的重复项,所以我们需要先排序,再uniq:
linux@myccloves:~/test$ cat 1.txt | sort -n | uniq -c
4 0
1 1
1 2