grep、sed、awk是shell脚本编写中最常用到的三个工具
因为grep平时已经很熟悉了,这里就不介绍了,主要讲讲sed和awk工具
sed是一个”流处理编辑器”,可以用于自动处理文件,分析日志文件,修改配置文件,它接收文本或管道的输入,读入一行到模式空间(临时缓冲区),sed命令处理行,最后输出到屏幕,然后再次读入一行,继续上面流程,直到读完为止
使用sed的格式:
命令行格式:sed [options] ‘命令’ file(s)
脚本格式:sed -f scriptfile file(s) tip:命令还可以写在一个脚本文件里调用
options有 -n 、-e是比较常用的,命令:行定位(正则)+sed命令(操作)
p命令:打印行命令
例子:sed -n '5p' hello.txt
5代表第五行,打印第五行的内容,-n表示打印出命令操作的行,不加-n会打印出所有的行(包括经过操作之后的行)
不光可以用行号选择行,还可以用正则方式选择:sed -n '/wu/p' hello.txt,注意:正则表达式要用//两个斜杠包含在中间
上面是定位一行,还可以定位多行:sed -n '3,8p' hello.txt(打印出第三到第八行的内容)
当然行号也可以用正则替代:sed -n '/pid/,/hehe/p' hello.txt
还可以进行取反操作:sed -n '3!p' hello.txt(将除了第三行以外的行打印出来)
a命令:新增行命令
例子:sed '5a *************************' hello.txt
a命令将在第五行之后添加新的一行,内容为**************************
同样的,sed '1,5a ##############' hello.txt,将在第一到第五每行的后面都添加新的一行,行号也同样可以用正则替代
例子2:sed '$a \ port:9001 \n loginName:haha' config
解析:sed命令将在config文件的末尾($),添加新的两行(有\n),\n到login之间的空格也同样会打印在新的一行,至于port之前的空格,因为
a命令和内容之间本来就有空格,所以以\表示内容的开始,\到port之间的空格就是第一行前面的空格
i命令:插入行命令
例子:sed '5i *************************' hello.txt
i命令将在第五行之前添加新的一行,内容为**************************
c命令:替换行命令
例子:sed '5c *************************' hello.txt
c命令会将第五行替换成**************************
注意:sed '1,5c **************' hello.txt,不是将第一到第五每行都替换成*******,而是将第一到第五这五行替换成************
d命令:删除行命令
例子:sed '5d' hello.txt
d命令将删除第五行
例子2:sed '/^$/d' hello.txt
删除文本文件中的空行,/^$/代表空行
s命令:替换字符串命令
格式:s+分隔符+旧字符串+分隔符+新字符串+分隔符,分隔符可以是/或#等等
旧字符串当然也可以用正则来匹配
例子:sed 's/false/true/' passwd,将passwd文件中的每一行的第一个false替换成true,若你想让每一行的所有false都替换成true,则只需
sed 's/false/true/g' passwd,加上g选项将替换每一行所有的匹配的字符串
&符号:替换固定字符串
配合s命令使用
例子:sed 's/^[a-z]\+/& /' passwd
将passwd文件中,以[a-z]\+为开头的行的[a-z]\+替换成原来的字符串加上若干空格,&就是代表前面的旧字符串
()符号:提取字符串
同样配合s命令使用
例子:sed 's/\(^[a-z_-]\+\):.*$/\1/' passwd
首先匹配[a-z_-]\+开头的行,这里还用\(\)将开头括了起来,注意反斜杠的转义,标注我们要提取它,在后面用\1表示我们要提取第一个
用()括起来的子字符串,如果还有第二个(),则用\2表示
总之就是首先用正则匹配你需要的行,用()括起你想提取的字符串,最后用\1,\2等等表示你要提取的字符串
awk也是一个文本与数据处理工具,但是awk是可编程的,更灵活强大
awk的处理方式和格式:
awk一次处理一行内容,而且对每行可以进行切片处理
格式与sed差不多:
命令行格式:awk [options] ‘{command}’ file,而command格式:pattern{awk操作命令}
pattern:正则表达式和逻辑判断式
awk操作命令:内置函数:print()、printf()、getline()……..控制指令:if(){…..}else{…..};while(){…….};
脚本格式:awk -f scriptfile file(s)
awk内置参数应用:
awk内置变量:
- $0:表示整个当前行
- $1:表示每行第一个字段
- $2:表示每行第二个字段
....以此类推
- NR:每行的记录号(行号)
- NF:每行的字段数
- FILENAME:正在处理的文件名
awk内置参数:分割符
options: -F filed-separator(不指定,默认为空格)
例如:awk -F ':' '{print $3}' /etc/passwd
在passwd文件中,以每行的:(冒号)为分割符,打印出每行的第三个字段,print命令会在打印一行之后,默认换行
若要打印多个字段:awk -F ':' '{print $1,$2,$3}' /etc/passwd,以逗号分隔的话,则在打印出的字段之间会以空格分隔,根据print工具的用法,也可以打印制表符:print $1 "\t" $2来分隔字段,也可以加些说明文字,awk -F ':' '{print "user:"$1"\t""pass:"$2}' /etc/passwd。awk制表的原理差不多就是这样来的
除了用print还可以用printf()来打印,例子:awk -F ':' '{printf("Line:%3s Col:%s User:%s\n",NR,NF,$1)}' passwd,就像C++里的printf()一样
awk控制指令:
if(){…..}else{…..};while(){…….};
例子:awk -F ‘:’ ‘{if ( 3>100)print"Line:"NR,"User:" 3 > 100 ) p r i n t " L i n e :" N R , " U s e r :" 1}’ passwd
若每行的第三字段大于100则输出那行的行号和字段1
pattern:
之前提到command格式:pattern{awk操作命令},pattern有正则表达式和逻辑判断式
逻辑判断式:
例子:awk -F ':' '$2==100{print $1,$3}' passwd
若当前的第二字段等于100则输出$1和$3,当然也有<,>,<=,>=,!=
正则表达式:
例子1:awk -F ':' '/ERROR/{print $1}' test.log
输出匹配/ERROR/正则的那行的第一个字段
例子2:上面是用整行来匹配正则,当然也可以用某个字段来匹配
比如:awk -F ':' '$2~/^m.*/{print $0}' passwd,循环遍历每行,若第二个字段匹配/^m.*/则输出那行,若是判断"不匹配",则用!~
awk扩展格式:
例子:awk -F ':' 'BEGIN{print "Line Col User"}{print NR"\t"NF"\t"$1}END{print "------"FILENAME"------------"}' passwd
制表显示每行的行号,每行列数,对应行的用户名
{print "Line Col User"}输出表格的表头,{print "------"FILENAME"------------"}输出表的表尾
例子2:统计当前目录下所有文件的大小
ls -l | awk 'BEGIN{size=0}{size+=$5}END{print "size is "size/1024/1024"M" }'
例子3:统计passwd中的账户总数
awk -F ':' 'BEGIN{count=0}$0!~/^$/{count++}END{print "count= "count}' passwd
例子4:统计显示UID>100的用户名
awk -F ':' 'BEGIN{count=0}{if ($3>100) name[count++]=$1}END{for(i=0;i
例子5:统计netstat -anp状态下分别为LISTEN和CONNECTED的连接数
netstat -anp | awk '$6~/CONNECTED|LISTEN/{sum[$6]++}END{for (i in sum)print i,sum[i]}'
awk和sed比较:
awk和sed都能处理文本
awk侧重于复杂逻辑处理
sed侧重于正则处理
当然他们也可以共同使用!