正则表达式
================================
1.作用
用人为规定一些特殊符号表示匹配字符串
适用场景:模糊匹配字符串
元字符: 正则表达式中具有特殊含义的字符,叫做元字符
2.常用的元字符
grep "^he" 1.txt -Hn //匹配行首he
(1) 逻辑或需要转义
grep "he\|ha" 1.txt -Hn
(2)不出现,或者出现一次 ?需要转义
grep "hel\?o" 1.txt -Hn
问号需要转义
l\?表示l不出现,或者l出现一次
(3)出现一次,后者出现多次 +需要转义
grep "hel\+o" 1.txt -Hn
(4)指定重复次数 {}左右两边需要转义
grep "hel\{2,4\}o" 1.txt -Hn
awk和sed两个工具的使用
================================
1.awk处理表格中列
安装awk: sudo apt-get install awk
作用:主要用于统计表格中的信息,打印列
注意的要点:
第一: 搜索字符串
awk '$0~/你要匹配的字符串/ {print}' 要搜索的文件名
.* 表示匹配任意长度的字符串
2.sed也能处理表格数据
安装sed: sudo apt-get install sed
作用:字符串的增删改查都可以
命令总结:
第一:替换
sed "s/旧字符串/新的字符串/" people.txt
awk编程入门
测试文档:(grade.txt)
M.Tansley 05/2013 48311 Green 8 90
J.Lulu 04/2012 48317 green 12 88
P.bunny 02/2013 48 Yellow 9 70
J.Troll 09/2013 4842 Brown-3 11 95
L.Tansley 05/2013 4712 Brown-2 10 85
Vincent 07/2012 4712 Brown 13 87
1,打印指定列(例如名字和年龄)
awk '{print $1,$5}' grade.txt
注意:其中单引号中的被大括号括着的就是awk的语句,只能被单引号包含。
其中的$1..$n表示第几例。$0表示整个行。
注意:awk的工作次序是:首先读取grade.txt文件一个记录(即一行),然后根据单引号内部的指令工作,完了之后继续读下一行,以此类推。每读一行都会将单引号里面的语句从头到尾地应用到那一行中去。
2,格式化输出(和C语言一样一样的)
awk '{printf"%-10s:%-d\n", $1,$5}' grade.txt
3,过滤
awk '$5==11 && $6>=90 {print $0}' grade.txt
意思是==>打印出年龄等于11岁且分数大于90分的孩子的信息
4,打印表头,引入内建变量NR
awk 'NR==1 || $6>=90 {print}' grade.txt
注意:NR是一个所谓的内建变量,表示已经读出的记录数(即行号)
其它有用的内建变量是:
$0
当前记录(这个变量中存放着整个行的内容)
$1~$n
当前记录的第n个字段,字段间由FS分隔
FS
输入字段分隔符 默认是空格或Tab
NF
当前记录中的字段个数,就是有多少列
NR
行号,从1开始,如果有多个文件这个值将不断累加。
FNR
当前记录数,与NR不同的是,这个值会是各个文件自己的行号
RS
输入的记录分隔符, 默认为换行符
OFS
输出字段分隔符, 默认也是空格
ORS
输出的记录分隔符,默认为换行符
FILENAME
当前输入文件的名字
5,指定分隔符
awk ‘BEGIN{FS=”:”} {print $1}’ /etc/passwd
注意:BEGIN意味着紧跟在它后面的语句{FS=”:”}会在awk读取第一行之前处理。
上面的语句等价于
awk -F: ‘{print $1}’ /etc/passwd
如果有多个分隔符,则可以写成
awk -F’[\t;:]’ ‘{print $1}’ /etc/passwd
6,使用正则表达式匹配字符串
awk '$0~/Brown.*/ {print}' grade.txt 意思是==>将所有包含Brown的行打印出来
注意:波浪号~后面紧跟着一对正斜杠,表示所指定的域(这里是$0)要匹配的规则
7,使用模式取反的例子
awk '$0!~/Brown.*/ {print}' grade.txt 意思是==>将所有不包含Brown的行打印出来
拆分文件
8,将各年龄段的孩子的信息分别存放在各个文件中
awk 'NR!=1 {print > $5}' grade.txt
意思是==>表头不处理,后面的每一行,都将被重定位到以第5个域(年龄)命名的文件中去。
也可以将指定的域重定位到相应的文件
awk 'NR!=1 {print $1, $6 > $5}' grade.txt
意思是==> 不处理表头,将每一行中的姓名和分数重定位到与其年龄相应的文件中去。
9,再复杂一点,按级别将信息分成三个文件:
awk 'NR!=1 {if($4~/Brown.*|Black/) print > "high.txt";
else if($4~/Yellow|[Gg]reen/) print > "midle.txt";
else print > "low.txt"}' grade.txt
意思是==> 如果记录中的第4个域($4)匹配Brown.*或者Black,就将该记录重定位到文件high.txt中,如果匹配Yellow或者[Gg]reen,就重定位到midle.txt中,否则统统重定位到low.txt中。
统计
10,将所有孩子的分数累积起来并打印出来
awk '{sum+=$6} END{print sum}' grade.txt
注意:END表示->紧跟其后的语句只会在awk处理完所有行之后才被执行。
11,统计各个级别的人数
awk 'NR!=1 {a[$4]++;} END{for(i in a) print i","a[i];}' grade.txt
注意:$4是级别名称,例如Yellow、Brown等,a是一个以这些级别为下标的数组,其值从零开始计算。i就是Yellow、Brown等 a[i]是对应有几个Yellow、Brown 中间用逗号隔开
awk脚本
12,想象我现在要打印出整个班级的所有孩子的信息,而且在最前面把表头也打印出来,而且下面要打印一行“===========”来跟具体内容加以划分。并且在最后一行,统计孩子们的平均年龄以及平均分数。将awk语句组织成脚本,如下:
#!/usr/bin/awk -f
#/usr/bin/awk指定脚本解释器的位置,-f表示运行该脚本需要指定一个文件作为输入
BEGIN{ #awk开始运行之前的准备工作(定义了两个变量),此左花括号必须紧跟BEGIN
age = 0
score = 0
}
{
if(NR==1) #打印表头已经分割线
{
print $0
printf "==============================" #由于是printf,没有\n就不换行
print "==============================" #由于是print,会自动换行
}
else
{
age+=$5
score+=$6
print $0
}
}
END{ #awk处理完所有的记录之后,END才开始运行
printf "=============================="
print "=============================="
print "Average:\t\t\t\t\t" age/NR ",\t" score/NR
}
关于sed
测试文档:(people.txt)
Jack is 18-year old, he comes from US.
Mike is 16-year old, he comes from Canada.
Chen is 21-year old, he comes from China.
Lau is 18-year old, he comes from HongKong.
Michael is 20-year old, he comes from UK.
Phoebe is 18-year old, she comes from Australie.1,替换:
例如,将"-year"改成" years":
sed "s/-year/years/" people.txt2,指定某些行替换:
例如,将第2行的"-year"改成" years":
sed "2s/-year/years/" people.txt再如,将第2至5行的"-year"改成" years":
sed "2,5s/-year/years/" people.txt3,直接通过sed修改原文,加选项 -i:
sed -i "2s/-year/years/" people.txt
注意:sed缺省状态下不会修改原文4,替换每一行中的所有的小写s成大写S:
sed "s/s/S/g" people.txt
注意:g的意思是一行中所有的匹配项,否则缺省只会匹配第一个s5,替换每一行中的第2个小写s成大写S:
sed "s/s/S/2" people.txt6,替换每一行中的第2个以后的小写s成大写S:
sed "s/s/S/2g" people.txt多个匹配
7,将"-year"改成" years",并且将第3行以后的最后一个任意字符去掉:
sed 's/-year/ years/; 3,$s/.$//' people.txt
以上命令等价于:
sed -e 's/-year/ years/' -e '3,$s/.$//' people.txt
注意:在单引号里面,元义字符可以直接使用,如果要去掉元义则要在前面加\ ; 在双引号里面,sed的命令要使用元义,则需要加\ , 而命令的正则表达式要使用元义直接使用就行。
8,将&代替被匹配的变量:
sed "s/is/[&]/" people.txt
意思是==>:将文本中每一行出现的第一个is的左右两边加上[ ]9,如果使用正则表达式匹配项的时候使用了圆括号括了起来,那么可以用\1,\2,\3……等来表示这些项:
sed "s/\(^.*\)\tis.*from \(.*\)./\1\t:\2/g" people.txt
分解一下:
1,其中加粗的\(^.*\)\tis.*from \(.*\).是正则表达式,简化一下是(^.*)\tis.*from (.*). 在这个表达式中,制表符\t前面的匹配项可以被记为\1,from后面的匹配项可以被记为\2
2,后面加下划线的\1\t:\2部分是替换的字符串,也就是只打印匹配出来的名字和国籍,中间用制表符和冒号隔开。10,提前预读多一行缓冲来进行匹配:
sed 'N;s/is/IS/' people.txt
注意:由于替换只会针对第一个出现的单词is,而通过N又多读了一行,因此这个命令的结果是只会替换奇数行。11,在指定行的前面插入(i)或者后面插入(a)一些信息:
sed '3i abcd' people.txt 意思是==>在第3行的前面插入abcd
sed '2a abcd' people.txt 意思是==>在第2行的后面插入abcd
sed '1,4a abcd' people.txt 意思是==>在第1至4行的后面分别插入abcd
sed '/US/a abcd' people.txt 意思是==>在匹配US的行的后面插入abcd12,将指定的行替换成其他信息:
sed "2c ok" people.txt 意思是==>将第2行替换成ok13,将指定的行删除掉:
sed ‘2d’ people.txt 意思是==>将第2行给删掉
sed ‘/US/d’ people.txt 意思是==>将匹配/US/的所有行给删掉
sed '/\<he\>/d' people.txt 意思是==>将匹配he的所有行给删掉,注意:之所以要用<>将he给括起来,是因为不想匹配she,当然,<>需要转义,写成\<\>14,打印指定匹配的行,用命令p:
sed '/Chen/p' people.txt -n 意思是==>打印匹配Chen的行
sed '/Chen/, /Lau/p' people.txt -n 意思是==>打印匹配Chen或者Lau的行
sed '3,/UK/p' people.txt -n 意思是==>从第3行开始打印,直到匹配UK为止
sed '/UK/,6p' people.txt -n 意思是==>从匹配UK的行开始打印,直到第6行为止15,使用相对位置:
sed '/US/, +2p' people.txt -n 意思是==>打印匹配US的行,并打印其后的2行。16,执行多个命令:
sed '{/he/{/18/p}}' people.txt -n 意思是==>匹配所有/he/的行之后,再匹配/18/的行,然后打印出来。