sed和awk的简单学习笔记
之前我做一些基本的文本处理也都是喜欢用perl来写脚本实现。这样做还是比较麻烦,效率也不高,其实可以使用SED和AWK的一些基本(组合)命令来实现。
SED和AWK也可以支持脚本,不过如果要写脚本的话,我倒更愿意去写Perl的脚本了。所以下面的例子基本都是一行命令的处理例子。
-------------- SED---------------
例子1:
给每一行后面都加一行“000”的行---》比如,NE的testpattern全是y的,需要给它加上uv分量。
sed -e 'a\\
? 000' t.txt
注意:上面是2行,必须用换行符,否则就得用sed脚本-f了
如果是每2行增加2行00:
sed -e 'n;a\\
?00\n00' tt.txt
例子2:
删除奇数行(只要偶数行)
sed -n -e 'n;p' t.txt
分析: -n是不打印,如果不加-n,会导致偶数航被打印2次。 'n;p'的意思是下一行打印。用这个方式来剔除了奇数行
例子3:
删除偶数行(只要奇数行)
sed-e 'n;d' t.txt
分析: 用d直接把偶数行删除了
例子4:
只打印指定字符串"lisj"的行(类似于grep)
sed -e '/lisj/p' -n t.txt
例子5:
删除第一行
sed -e '1d' t.txt
删除第1到第4行
sed -e '1,4d' t.txt
删除第1行到第一个包含指定字符串“study”的行
sed -e '1,/study/d' t.txt
删除第一个包含指定字符串“compiler”到第一个指定字符串“study”的行
sed -e '/compile/,/study/d' t.txt
例子6:
为每一行前面加上“[ ]”
sed 's/^/[ ]/g' t.txt
为每一行后面加上"[ ]"
sed 's/$/[ ]/g' t.txt
例子7:
显示匹配行的行号
sed '/sed/=' t.txt
sed '/sed/=' -n t.txt
注意:如果不加-n选项,则会打印整个文件和匹配行的行号。加了-n就会只打印匹配行的行号
sed -n-e '/sed/=' -e '/sed/p' t.txt
分析: 这样就会打印匹配行的行号和匹配航的内容
sed -n -e '/sed/p' -e '/sed/=' t.txt
分析: 只是与上面命令的显示顺序不一样
例子8:
限定范围以后的模式匹配和替换。 把所有包含指定字符串“sed”的行里的第一个e改成“EE”
sed '/sed/s/e/EE/' t.txt
例子9: &用法,获取前面匹配的内容
把“sed”,换成“sed ABC”
sed 's/sed/& ABC/' t.txt
把所有含“sed”的行用()括起来
sed '/sed/s/.*/(&)/' t.txt
例子10: \1用法,类似于perl的匹配时候的$1
把每行里第一个“li”替换成“li+gyl”
sed 's/\(li\)/\1+gyl/' t.txt
注意: \(li\)
例子11:只打印1到4行里包含“sed”的行
sed -n -e '1,4p' t.txt | sed -n -e '/sed/p'
例子12:!用法
只保留文件的1到4行
sed -e '1,4\!d' t.txt
注意: 我发现得用\!来转义,但是书上看到的例子却没有用转义
-----------------AWK----------
假设t.txt内容是:
namebirthdayagegenderbegin_working
lishujie1980/10/1732Male24
gongyanli1981/10/2031Female26
liyuxuan2008/09/214Female4
例子:把一个文件的第一行去掉,然后选取每行的第一个域和第四个域,并且在文件一开始增加内容,文件末尾增加内容
sed '1d' t.txt | awk 'BEGIN {print "Namegender \n----------------"}{print $1,$4} END {print"End-of-print"}'
注意:AWK默认以空格来区分域。如果不是空格的话需要用 -F seperate-operator来指定。
AWK里的正则匹配~ 不匹配!~
例子:把匹配某字符串的行打印出来
awk '{if($4~/Female/) print $0}' t.txt
注意:$0是指的把正行都打印出来。if实现精确的匹配,也可以不用if。比如上述命令简化为 awk '$0 ~ /Female/' t.txt
再比如:
awk '$3 == 31' t.txt
awk '/^li/' t.txt
awk '{if($3 == 31 && $1=="gongyanli") print $0}' t.txt
awk '{if($3 == 31 || $1=="lishujie") print $0}' t.txt
AWK里的内置变量。内置变量比较多,建议看参考书。举几个例子:
FILENAMEawk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行- F选项
NF浏览记录的域个数
NR已读的记录数
例子:获取文件行数
awk 'END{print NR}' t.txt
例子:在每行前面加上 域个数、行号;在最后加上文件名信息
awk '{print NF,NR,$0} END {print FILENAME}' t.txt
例子:从PWD中抽取文件夹名
echo `pwd` | awk -F / '{print $NF}'
给域设置域变量名,方便使用
awk '{name=$1;age=$3;if(name=="lishujie") print name"'\''s age is "age}' t.txt
注意:这里牵扯到了如何在AWK里打印单引号的问题。
解决方法是 把转义的单引号 ‘ 用两个单引号括起来并且加上转义符号,使其不执行
设置局部的变量:
awk '{name=$1;age=$3;max_age=31 ;if($3<max_age) print name"'\''s age is "age}' t.txt
在awk里实现运算:
awk '{name=$1;age=$3 ;age=age+1; if (name !~ /name/) print "Next year "name"'\''s age is "age}' t.txt
修改域值:
awk '{if ($1 ~ /lishujie/) $1 = "dad" ; if ($1 ~ /gongyanli/) $1 = "mum" ;print $0}' t.txt
这个还是会把所有的记录都打印出来,如果想只打印修改的记录怎么处理呢?
awk '{if ($1 ~ /gongyanli/) {$1 = "mum" ;print $0}}' t.txt
注意: 使用大括号来设置命令的执行范围就可以了。
增加一列参数“working_year” 并且计算数值。
第一行表头处理方法:
awk '{if (NR == 1) printf "%s\t working_year\n",$0}' t.txt
注意:这里用printf来实现去掉$0里的换行符。
后面数据处理方法:
awk '{if (NR > 1) {working_year = $3-$5;printf "%s\t%d \n",$0,working_year}}' t.txt
把上述两个命令合并在一起就可以了
awk '{if (NR == 1) printf "%s\t working_year\n",$0} {if (NR > 1) {working_year = $3-$5;printf "%s\t%d \n",$0,working_year}}' t.txt
统计列值的累加值:
awk '{tot+=$3;print $0}END{print "tot age is "tot}' t.txt
不打印文件内容,只统计列值的话,就不要“print $0”
awk '{tot+=$3}END{print "my family total age is "tot}' t.txt
嚓,不好意思,word文档里的空行帖子里都没了。
高手啊啊啊啊啊
sed和awk对文本的处理效率还是挺高的,赞一个,好好学习。
gao shou
学习中,谢谢分享。
非常有用哦。
真是个好论坛啊
熟悉sed和awk可以方便很多啊
学习学习!
以前不太懂也不太会用sed awk,现在发现这个简直就是神器啊,可以省不少的力
mark!thanks!
学习了