文本处理三剑客:grep sed awk
grep,egrep,fgrep:文本过滤工具:
sed:行编辑器
模式空间、保持空间
awk:报表生成器,用于格式化文本输出工具;
基本用法:
awk命令软连接到gawk
gawk [options] 'program' FILE...
program: PATTERN{ACTION STATEMENTS}
语句间用分号分隔
选项:
-F:指明输入时用到的字段分隔符;
-v:var=value用于实现自定义变量
处理文本原理:
一次读取一行文本,首先会把文本通过指明输入分隔符分成n个组成部分
并且将每一片保存在awk的内键变量中,仅显示某一段某些段,显示整段用$0
我们可以随意指定某一个片段,进行模式判断。也可以对每一个片段进行循环加工;循环功能主要用于在字段间进行循环遍历。总结,文本报告输出的工具。
tail -5 /etc/fstab | awk '{print $2,$4}'显示第二个字段和第四个字段,不加逗号会将两个字段连接在一起,加逗号默认以空白字符分隔
一、print
print item1,item2.....
要点:
(1)逗号分隔符
(2)输出的各item可以是字符串,也可以是字符;当前记录的字段、变量或awk的表达式;
(3)省略item,相当于print $0;
tail -5 /etc/fstab | awk {print $2 $4}
/defaults
/bootdefaults
/usrdefaults
swapdefaults
tail -5 /etc/fstab | awk '{print $2,$4}' 瞬间发现有“,”和没有区别是很大的,加,默认为空格,不加就会连接在一起
/ defaults
/boot defaults
/usr defaults
swap defaults
[root@localhost ~]# tail -5 /etc/fstab | awk '{print "hello:"$1}'hello:UUID=bd3f9d54-f9f2-48df-9441-0050d0e60b4ahello:UUID=81b1d5b7-48ab-41e4-a34a-f865a015d23chello:UUID=c36a0583-ac95-40bc-bb81-eed920e34ec5hello:UUID=9cc0349f-9faa-4bba-8ef7-689d60280aedhello:[root@localhost ~]# tail -5 /etc/fstab | awk '{print "hello:$1"}' 瞬间你会发现$1 变量引用是不可以放在双引号里面的hello:$1hello:$1hello:$1hello:$1hello:$1
二、变量
内建变量
FS:默认为空白字符
awk '{print $1}' /etc/passwd 以空白分隔显示第一段 awk -v FS=':''{print $1} ' /etc/passwd 指明输出分隔符为冒号
NF:每一行的字段数量
awk '{print NF}' /etc/fstab 为每一个行统计字段数量 {print $NF}
NR:打印每一行的行号
awk '{print NR}' /etc/fstab 相当于set nu
FILENAME:打印当前文件名
awk '{print FILENAME}' /etc/fstab /etc/issue 打印出两个文件的名称
ARGC:命令行参数的个数
awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue
ARGV:数组,保存的是命令行所给定的各参数
awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue
OFS:默认为空白字符
RS:输入时的换行符,一行中只要有空格,就当做换行
ORS:输出时的换行符
自定义变量
-v var=value
变量名区分字符大小写
在program中直接定义
~]#awk -v test='hello gawk' '{print test}' /etc/fstabhello gawk hello gawk hello gawk hello gawk hello gawk hello gawk hello gawk hello gawk hello gawk hello gawk hello gawk hello gawk hello gawk~]#awk -v test='hello gawk' 'BEGIN{print test}'hello gawk
~]#awk '{test="hello gawk";print test}'
~]#awk -v test='hello gawk' 'BEGIN{print test}'
hello gawk
三、printf命令
格式化输出:print FORMAT,item1,item2,...item会显示在FORMAT事先准备的格式中
(1)FORMAT必须给出
(2)不会自动换行,需要显式给出行号控制符,\n
(3)FORMAT中需要分别为后面的每个item指定一个格式化符号
格式符:
%c: 显示字符的ASCII码;
%d, %i: 显示十进制整数;
%e, %E: 科学计数法数值显示;
%f:显示为浮点数;
%g, %G:以科学计数法或浮点形式显示数值;
%s:显示字符串;
%u:无符号整数;
%%: 显示%自身;
awk -F: '{print $1}' /etc/passwdawk -F: '{printf "%s\n",$1}' /etc/passwd 显示用户名,一行一个,不加%s就会乱成一坨awk -F: '{printf "Username:%s, UID:%d\n,"$1,$3}' /etc/passwd
修饰符:
#[.#]: 第一个数字控制显示的宽度,第二个字符表示小数点之后的精度
例: %3.1f
awk -F: '{printf "Username:%15s,"}' /etc/passwd 默认右对齐
-:左对齐
+:显示数值的符号
四、操作符
算数操作符
x+y,x-y, x*y, x/y, x^y,
-x
+x:转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=, +=, -=, *=, /=, %=, ^= ,++, --
比较操作符:
>, >=, <, <=, !=, ==
模式匹配符:
~:是否匹配
!~:是否不匹配
逻辑操作符:
&&
||
!
函数调用:
function_name(argu1,argu2,.....)
条件表达式:
selector?if-true-expression:if-false-expression
# awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd
五、PATTREN:
类似于sed中的地址定界
(1)empty:空模式,匹配每一行
(2)/regular expression/:仅处理能够被此处模式匹配到的行
awk '/^UUID/{print $1}' /etc/fstab 取UUID开头的行awk '!/^UUID/{print $1}' /etc/fstab 上题取反
(3)relational expression:关系表达式,结果有真有假;结果为真才会被处理;真;结果为非0值,非空字符串
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd 显示最后一个字段为/bin/bash的行的第一个字段和最后一个字段awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd "~"的意思是是否匹配
(4)line ranges 行范围
注意:不支持直接给出数字的格式
awk -F: '/^root/,/^myuser/{print $1}' /etc/passwd 从第一次匹配到root到第一次匹配到myuser结束中间所有的用户名都显示出来awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd 打印行号大于2和小于10的行的第一个字段
(5)BEGIN/END模式
BEGIN{program段}:尽在开始处理文件的中的文本之前执行一次
END{}:尽在文本处理完成之后执行一次
awk -F: 'BEGIN{print " username uid \n-----------"}'程序开始之前执行一次awk -F: 'BEGIN{print " username uid \n-----------"}END{print $1,$3}' /etc/passwd 程序结束之前执行一次
六、常用的action
(1)Expression:表达式语句
(2)控制语句:if while
(3)组合语句:
(4)输入语句:
(5)输出语句:
七、控制语句
在一行当中实现循环语句的使用
if(condition) {statments}
if(condition) {statments} else {statments}
while(conditon) {statments}
do {statments} while(condition)
for(expr1;expr2;expr3) {statements}
break
continue
delete array[index]
delete array
exit
{ statements }
7.1 if-else
语法:if(condition) statement [else statement]
~]#awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd UID大于等于1000就显示用户名和id号 普通用户~]#awk -F: '{if($3>=1000) printf "Common user: %3\n",$1 else {printf "root or Sysuser:%3\n",$1}}' /etc/passwd
使用场景:对awk取得的整行或某个字段做条件判断
awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
字段数大于5就显示出来,否则不予以显示awk '{if(NF>5) print $0}' /etc/fstab
df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}'如果一个设备使比例大于80就取出来
7.2 while循环
语法:while(condition) statement
条件“真”进入循环;条件“假”退出循环
使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各个元素注意处理时使用;
awk '/^[[:space:]]*linux16/{(i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg显示文件中每一个符合条件的行(含有linux16),行内的每一个字段,字段的本身和字符个数。length():计算字符个数若我现在只想显示大于等于7的字段awk '/^[[:space:]]*linux16/{(i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg
7.3 do-while循环
语法:do statement while(condition)
意义:至少执行一次
7.4 for循环
语法:for(expr1;pxpr2;pxpr3) statement
特殊用法:
能够遍历数组中的元素:
语法:for (var in array) {for-body}遍历数组的下标
若要遍历数组中的每个元素,要使用for循环;
for (var in array) {for-body}
awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($1)}}' /etc/grub2.cfg
显示文件中每一个符合条件的行(含有linux16),行内的每一个字段,字段的本身和字符个数。
注意var会遍历array的每个索引
netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}'格式:state["LISTEN"]++ state["ESTABLISHEB"]++显示netstat -tan 每个TCP状态出现了多少次
awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log对每一个在我服务器上获取资源次数的ip地址做统计
awk '/^UUID/{fs[$3]++}END{for(i in fs) {print (i in fs) {print}}' 未完.....统计/etc/fstab文件中每个文件系统出现的次数
awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) }' 未完.....统计指定文件中每个单词出现的次数
7.5 switch语句
(类似于case)
语法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}
case是关键字后面可以是一个值,或者是一个模式 default 为默认分支
7.6 break和continue
break [n] 退出n层循环
continue 让当前循环提前结束,而进行下一轮
7.7 next
提行结束对本行的处理,而直接进入下一行
awk -F: '{if($3%2!=0)} next; print $1,$3' /etc/passwdID号为偶数的用户名的显示出来八、 array数组
关联数组:array[index-expression]
index-expression:
(1)可以使用任意字符串
(2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为"空串":
(3)若要判断数组中是否存在某元素,要使用"index in array"
weekdays[mon]="monday"
awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}' 字符串要使用双引号,不要乱用单引号awk 'BEGIN{weekdays["mon"]"Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays{i}}}'九、函数
9.1内置函数
数值处理:
rand():返回0和1之间一个随机数
awk 'BEGIN{print rand()}' 重复执行随机数不会变,可以调用第一次执行结果字符串处理:
length([S]):返回指定字符串的长度
sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容
awk -F: '{print sub(o,O,$0)}' /etc/passwd找/etc/passwd 第一次匹配到o替换为O 有print表示是否替换成功 ,一般不用printgsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容;
split(s,a[],r):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中
netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'统计每一个IP对我们主机建立了多少次连接