Linux正则表达式相关命令
正则表达式
正则表达式:计算机科学的一个概念,使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。
选择
|
竖直分隔符表示选择,例如boy|girl
可以匹配boy
或者girl
数量限定
+
表示前面的字符必须出现至少一次(1次或多次),例如ab+cd
,可以匹配abcd
,abbcd
等?
表示前面的字符最多出现一次(0次或1次),例如colou?r
,可以匹配color
或者colour
*
星号代表前面的字符可以不出现,也可以出现一次或者多次(0次、1次或多次),例如0*42
可以匹配42
、042
、0042
、00042
等
范围和优先级
()
圆括号可以用来定义模式字符串的范围和优先级,这可以简单的理解为是否将括号内的模式串作为一个整体。例如,gr(a|e)y
等价于gray|grey
(这里体现了优先级,竖直分隔符用于选择a
或者e
而不是gra
和ey
),(grand)?father
匹配father
和grandfather
(这里体现了范围,?
将圆括号内容作为一个整体匹配)
更多语法
字符 | 描述 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符。 例如,n 匹配字符n ,\n 匹配一个换行符,序列\\ 匹配\ 而\( 则匹配( |
^ | 匹配输入字符串的开始位置 |
$ | 匹配输入字符串的结束位置 |
{n} | 匹配确定的n次(n为非负整数)。例如,o{2} 不能匹配Bob 中的o ,但是能匹配food 中的两个o |
{n,} | 至少匹配n次(n为非负整数)。例如,o{2,} 不能匹配Bob 中的o ,但能匹配foooood 中的所有o 。o{1,} 等价于o+ ,o{0,} 则等价于o* |
{n,m} | 最少匹配n次且最多匹配m次(m和n均为非负整数,其中n<=m)。 例如,o{1,3} 将匹配fooooood 中的前三个o 。o{0,1} 等价于o? 。请注意在逗号和两个数之间不能有空格 |
* | 匹配前面的子表达式零次或多次。例如,zo 能匹配z 、zo 以及zoo 。* 等价于{0,} |
+ | 匹配前面的子表达式一次或多次。例如,zo+ 能匹配zo 以及zoo ,但不能匹配z 。+ 等价于{1,} |
? | 匹配前面的子表达式零次或一次。例如,do(es)? 可以匹配do 或does 中的do 。? 等价于{0,1} |
限制符+? | 当该字符紧跟在任何一个其他限制符(* 、+ 、? 、{n} 、{n,} 、{n,m} )后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串oooo ,o+? 将匹配单个o ,而o+ 将匹配所有o |
. | 匹配除\n 之外的任何单个字符。要匹配包括\n 在内的任何字符,请使用像(.|\n)的模式 |
(pattern) | 匹配pattern并获取这一匹配的子字符串。该子字符串用于向后引用。要匹配圆括号字符,请使用\( 或\) |
x|y | 匹配x或y。例如z|food能匹配z 或food ,(z|f)ood则匹配zood 或food |
[xyz] | 字符集合,匹配所包含的任意一个字符。例如,[abc] 可以匹配plain 中的a 。其中特殊字符仅有反斜线\ 保持特殊含义,用于转义字符。其它特殊字符如星号、加号、各种括号等均作为普通字符。脱字符^ 如果出现在首位则表示负值字符集合,如果出现在字符串中间就仅作为普通字符。连字符- 如果出现在字符串中间表示字符范围描述;如果出现在首位则仅作为普通字符 |
[^xyz] | 排除型字符集合,匹配未列出的任意字符。 例如,[^abc] 可以匹配plain 中的plin |
[a-z] | 字符范围,匹配指定范围内的任意字符。 例如,[a-z] 可以匹配a 到z 范围内的任意小写字母字符 |
[^a-z] | 排除型的字符范围,匹配任何不在指定范围内的任意字符。例如,[^a-z] 可以匹配任何不在a 到z 范围内的任意字符 |
优先级
优先级 | 运算符 | 说明 |
---|---|---|
高 | \ | 转义符 |
(), (?:), (?=), [] | 括号和中括号 | |
*、+、?、{n}、{n,}、{n,m} | 限定符 | |
^、$、\任何元字符 | 定位点和序列 | |
低 | | | 选择 |
相关命令
grep模式匹配命令
基本操作
grep
命令用于打印输出文本中匹配的模式串,使用正则表达式作为匹配的条件。这个命令支持三种正则表达式引擎,用三种参数指定,在不使用perl语言的情况下用的大多数正则表达式都是前两种:
参数 | 说明 |
---|---|
-E |
POSIX扩展正则表达式,ERE |
-G |
POSIX基本正则表达式,BRE |
-P |
Perl正则表达式,PCRE |
grep
命令有如下常用参数:
参数 | 说明 |
---|---|
-b |
将二进制文件作为文本来进行匹配 |
-c |
统计以模式匹配的数目 |
-i |
忽略大小写 |
-n |
显示匹配文本所在行的行号 |
-v |
反选,输出不匹配行的内容 |
-r |
递归匹配查找 |
-A n |
n为正整数,表示after的意思,除了列出匹配行之外,还列出后面的n行 |
-B n |
n为正整数,表示before的意思,除了列出匹配行之外,还列出前面的n行 |
--color=auto |
将输出中的匹配项设置为自动颜色显示 |
使用基本正则表达式BRE
位置
-
查找
/etc/group
文件中以shiyanlou
开头的行:1
2grep 'shiyanlou' /etc/group
grep '^shiyanlou' /etc/group
数量
-
匹配以
z
开头以o
结尾的所有字符串:1
echo 'zero\nzo\nzoo' | grep 'z.*o'
-
将匹配以
z
开头以o
结尾,中间包含一个任意字符的字符串:1
echo 'zero\nzo\nzoo' | grep 'z.o'
-
将匹配以
z
开头,以任意多个o
结尾的字符串:1
echo 'zero\nzo\nzoo' | grep 'zo*'
选择
-
grep
默认是区分大小写的,接下来对字符串1234\nabcd
进行如下操作。 -
匹配所有的小写字母:
1
echo '1234\nabcd' | grep '[a-z]'
-
匹配所有的数字:
1
2echo '1234\nabcd' | grep '[0-9]'
echo '1234\nabcd' | grep '[[:digit:]]' -
匹配所有的小写字母:
1
echo '1234\nabcd' | grep '[[:lower:]]'
-
匹配所有的大写字母:
1
echo '1234\nabcd\nABCD' | grep '[[:upper:]]'
-
匹配所有的字母和数字,包括0-9,a-z,A-Z:
1
echo '1234\nabcd' | grep '[[:alnum:]]'
-
匹配所有的字母:
1
echo '1234\nabcd' | grep '[[:alpha:]]'
-
完整的特殊符号列表及说明:
特殊符号 | 说明 |
---|---|
[:alnum:] |
代表英文大小写字母及数字,亦即 0-9, A-Z, a-z |
[:alpha:] |
代表任何英文大小写字母,亦即 A-Z, a-z |
[:blank:] |
代表空白键与 [Tab] 按键两者 |
[:cntrl:] |
代表键盘上面的控制按键,亦即包括 CR, LF, Tab, Del… 等等 |
[:digit:] |
代表数字而已,亦即 0-9 |
[:graph:] |
除了空白字节 (空白键与 [Tab] 按键) 外的其他所有按键 |
[:lower:] |
代表小写字母,亦即 a-z |
[:print:] |
代表任何可以被列印出来的字符 |
[:punct:] |
代表标点符号 (punctuation symbol),亦即:" ’ ? ! ; : # $… |
[:upper:] |
代表大写字母,亦即 A-Z |
[:space:] |
任何会产生空白的字符,包括空白键, [Tab], CR 等等 |
[:xdigit:] |
代表 16 进位的数字类型,因此包括: 0-9, A-F, a-f 的数字与字节 |
排除
-
在字符串中排除字符:
1
echo 'geek\ngood' | grep '[^o]'
当
^
放到中括号内为排除字符,否则表示行首
使用扩展正则表达式ERE
通过grep
使用扩展正则表达式需要加上-E
参数,或使用egrep
数量
-
只匹配
zo
:1
echo 'zero\nzo\nzoo' | grep -E 'zo{1}'
-
匹配以
zo
开头的所有单词:1
echo 'zero\nzo\nzoo' | grep -E 'zo{1,}'
选择
-
匹配
www.shiyanlou.com
和www.google.com
:1
echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -E 'www\.(shiyanlou|google)\.com'
-
或者匹配不包含
baidu
的内容:1
echo 'www.shiyanlou.com\nwww.baidu.com\nwww.google.com' | grep -Ev 'www\.baidu\.com'
因为.
号有特殊含义,所以需要转义
sed流编辑器
-
sed
命令的基本格式如下:1
sed [参数]... [执行命令] [输入文件]...
常用参数
参数 | 说明 |
---|---|
-n |
安静模式,只打印受影响的行,默认打印输入数据的全部内容 |
-e |
用于在脚本中添加多个执行命令一次执行,在命令行中执行多个命令通常不需要加该参数 |
-f filename |
指定执行filename文件中的命令 |
-r |
使用扩展正则表达式,默认为标准正则表达式 |
-i |
将直接修改输入文件内容,而不是打印到标准输出设备 |
执行命令
-
sed
命令中可以有单条或多条执行命令,每条执行命令之间使用;
分隔,执行命令格式如下:1
2[n1][,n2]command
[n1][~step]command其中n1,n2表示输入内容的行号,它们之间为
,
逗号则表示从n1到n2行,如果为~
波浪号则表示从n1开始以step为步进的所有行;command为执行动作。 -
其中一些命令可以在后面加上作用范围,比如:
1
2sed -i 's/sad/happy/g' test
sed -i 's/sad/happy/4' test其中,第一句命令的
g
表示全局范围,第二句命令的4
表示指定行中第四个匹配的字符串,上面两句都是将范围内的sad
更改为happy
。 -
下面为一些常用动作指令:
命令 | 说明 |
---|---|
s |
行内替换 |
c |
整行替换 |
a |
插入到指定行的后面 |
i |
插入到指定行的前面 |
p |
打印指定行,通常与-n 参数配合使用 |
d |
删除指定行 |
操作举例
-
首先得到一个用于测试的文本文件:
1
cp /etc/passwd ~
-
打印指定行(2-5):
1
nl passwd | sed -n '2,5p'
-
打印奇数行:
1
nl passwd | sed -n '1~2p'
-
行内替换,将输入文本中"shiyanlou" 全局替换为"hehe",并只打印替换的那一行,注意这里不能省略最后的"p"命令:
1
sed -n 's/shiyanlou/hehe/gp' passwd
-
删除某行(30):
1
2
3nl passwd | grep "shiyanlou"
sed -i '30d' passwd
nl passwd | grep "shiyanlou"
awk文本处理语言
简单介绍
AWK
是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一,其名称得自于它的创始人Alfred Aho(阿尔佛雷德·艾侯)、Peter Jay Weinberger(彼得·温伯格)和Brian Wilson Kernighan(布莱恩·柯林汉)姓氏的首个字母.AWK程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”,它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。最简单地说,AWK是一种用于处理文本的编程语言工具。
-
在大多数linux发行版上面,实际使用的是gawk(GNU awk,awk的GNU版本),在ubuntu环境上,默认提供的是mawk,系统已经创建好了
awk
指向mawk的符号链接:1
ll /usr/bin/awk
基础概念
-
awk
所有的操作都是基于pattern(模式)—action(动作)对来完成的,如下面的形式:1
pattern {action}
-
awk
处理文本的方式,是将文本分割成一些“字段”,然后再对这些字段进行处理,默认情况下,awk
以空格作为一个字段的分割符,不过这不是固定的,你可以任意指定分隔符。
基本格式
-
awk
命令的基本格式如下:1
awk [-F fs] [-v var=value] [-f prog-file | 'program text'] [file...]
其中
-F
参数用于预先指定前面提到的字段分隔符(还有其他指定字段的方式) ,-v
用于预先为awk
程序指定变量,-f
参数用于指定awk
命令要执行的程序文件,或者在不加-f
参数的情况下直接将程序语句放在这里,最后为awk
需要处理的文本输入,且可以同时输入多个文本文件。
具体操作
-
先用
vim
新建一个文本文档:1
vim test
输入如下内容:
1
2I like linux
www.shiyanlou.com按下Esc,输入
:wq
保存并退出 -
使用
awk
将文本内容打印到终端:1
awk '{print}' test
-
将test的第一行的每个字段单独显示为一行,其他行则直接显示:
1
2
3
4
5
6awk '{
if(NR==1){
print $1 "\n" $2 "\n" $3
} else {
print}
}' test或者:
1
2
3
4
5
6
7awk '{
if(NR==1){
OFS="\n"
print $1, $2, $3
} else {
print}
}' test -
将test的第二行的以点为分段的字段换成以tab为分隔:
1
2
3
4awk -F'.' '{
if(NR==2){
print $1 "\t" $2 "\t" $3
}}' test或者:
1
2
3
4
5
6
7
8awk '
BEGIN{
FS="."
OFS="\t"
}{
if(NR==2){
print $1, $2, $3
}}' test
常见内置变量
变量名 | 说明 |
---|---|
FILENAME |
当前输入文件名,若有多个文件,则只表示第一个。如果输入是来自标准输入,则为空字符串 |
$0 |
当前记录的内容 |
$N |
N表示字段号,最大值为NF 变量的值 |
FS |
字段分隔符,由正则表达式表示,默认为" "空格 |
RS |
输入记录分隔符,默认为\n ,即一行为一个记录 |
NF |
当前记录字段数 |
NR |
已经读入的记录数 |
FNR |
当前输入文件的记录数,请注意它与NR的区别 |
OFS |
输出字段分隔符,默认为" "空格 |
ORS |
输出记录分隔符,默认为\n |
实战训练
-
辨析pattern space和hold space的概念
-
Pattern space(模式空间)
-
用于存储当前处理的文本行的缓冲区。在
sed
的处理过程中,文本逐行读取,每一行都被存储在Pattern space中,然后在Pattern space中进行模式匹配和操作。 -
当
sed
读取一行文本时,该行文本被放入Pattern space中,然后执行可能的操作,如查找和替换。处理完一行后,Pattern space中的内容可以被输出,也可以保留用于后续处理。
-
-
Hold space(保持空间)
-
用于在处理多行文本时保存额外的信息。与Pattern space不同,Hold space可以在不同的时刻存储不同的内容,而Pattern space则主要用于当前正在处理的行。
-
sed
提供的命令允许将Pattern space中的内容移动到Hold space中,反之亦然。这使得在处理多行文本时能够保留和操作先前处理的文本行的信息。
-
-
在
sed
脚本中,可以使用h
或H
命令将Pattern space的内容转移到Hold space,使用g
或G
命令将Hold space的内容转移回Pattern space,区别如下:
-
命令 | 说明 |
---|---|
g |
将hold space中的内容拷贝到pattern space中,原来pattern space里的内容被覆盖 |
G |
将hold space中的内容扩充到pattern space最后(换行) |
h |
将pattern space中的内容拷贝到hold space中,原来hold space里的内容被覆盖 |
H |
将pattern space中的内容扩充到hold space最后(换行) |
d |
删除pattern space当前行,并读入下一新行到pattern space中 |
D |
删除pattern space中的第一行,不读入下一行 |
-
基于pattern space和hold space实现将一个文本倒序输出
-
新建一个文本,作为实验内容:
1
vim testfile
-
输入以下内容,然后保存文件:
1
2
3
4
5
6line1
line2
line3
line4
line5
line6 -
查看写入内容:
1
awk '{print}' testfile
-
我们执行
sed
命令时能看到的输出都为Pattern space中的内容(当前处理的文本行的缓冲区),因此思路为借助Hold space对Pattern space当前的内容进行操作。 -
那么当前Pattern space在开始执行时依次存储的内容如下:
1
2
3
4line1 #第一次执行
line2 #第二次执行
line3 #第三次执行
line4 #第四次执行 -
现在希望将第一行放到第二行的后方,Pattern space变为如下内容:
1
2
3
4line1 #第一次执行
line2\nline1 #第二次执行
line3
line4 -
那么经过多次执行操作,最后Pattern space期望变为内容如下:
1
2
3
4line1 #第一次执行
line2\nline1 #第二次执行
line3\nline2\nline1 #第三次执行
line4\nline3\nline2\nline1 #第四次执行如果完成上述操作,则会输出内容如下:
1
2
3
4
5
6
7
8
9
10line1
line2
line1
line3
line2
line1
line4
line3
line2
line1由此看来,需要在每次扩展前一行到当前行的同时删除掉前一行的内容,最终仅保留最后一行的内容,即:
1
2
3
4#第一次执行后当前行被删除
#第二次执行后当前行被删除
#第三次执行后当前行被删除
line4\nline3\nline2\nline1 #第四次执行 -
整理思路得到对每一行执行的操作如下:
- 将当前行扩展到下一行(Pattern space)后方,中间使用
\n
分隔 - 删除当前行,然后读取下一行
- 将当前行扩展到下一行(Pattern space)后方,中间使用
-
但是,需要注意以下两个问题:
sed
命令中使用分号;
分隔的多个语句(①;②;③)如执行顺序为:第一行的 ① -> ② -> ③,然后才是第二行的 ① -> ② -> ③,以此类推。因为Pattern space是逐行读取的。- 使用程序完成第①步操作并非可以只用一步完成,应该是先在下一行后方添加换行符,然后将当前行内容扩展到下一行。
-
但如果对每一行都添加换行符,那么最终在
line1
的后方会多出一个多余的换行符,因此line1
的后方不应该添加换行符。同时“删除当前行”操作在直行道最后一行时,也不应该删除最后一行,否则会丢失所有行的内容。 -
那么最终的操作如下:
- 在每一行(除了第一行)后增加一个换行符(可以理解为将空内容换行扩展到当前行后方)
- 将当前行内容不换行扩展到下一行后方
- 将当前行删除(除非是最后一行),然后移动到下一行
-
这个步骤中的前两步也可以换种思路,其中暂存区借助Hold space实现:
- 将暂存区(开始时为空)内容换行扩展到当前行(除了第一行):
1!G
,第一行以外的行都执行G操作(将hold space中的内容换行扩充到pattern space最后) - 将当前行内容暂存:
h
,全部行都执行h操作(将pattern space中的内容拷贝到hold space中,原来hold space里的内容被覆盖) - 删除当前行,移动到下一行(除非是最后一行):
$!d
,最后一行以外的行都执行d操作(删除pattern space当前行,并读入下一新行到pattern space中)
- 将暂存区(开始时为空)内容换行扩展到当前行(除了第一行):
-
因此完整命令如下:
1
sed '1!G;h;$!d' testfile
-
-
基于pattern space和hold space实现交换奇数行和偶数行
-
将当前行存储到暂存区:
h
(将pattern space中的内容拷贝到hold space中,原来hold space里的内容被覆盖) -
如果不是最后一行,那么完成以下两步操作:
- 移动到下一行:
n
(将pattern space中的内容切换到下一行) - 在当前行末尾换行扩展暂存区内容:
G
(将hold space中的内容换行扩充到pattern space最后)
- 移动到下一行:
-
显示当前行:
p
-
由于已经在命令执行过程中显示了需要的内容,那么无需在执行完成后依次显示Pattern space的内容:
-n
,否则会显示如下内容:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#原内容
line1
line2
line1
#使用p进行的打印
line2
line1
#原内容
line3
line4
line3
#使用p进行的打印
line4
line3
#原内容
line5
line6
line5
#使用p进行的打印
line6
line5 -
那么完整命令如下:
1
sed -n 'h;$!{n;G};p' testfile
-