05-Linux文本处理-awk
Posted 广州富哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了05-Linux文本处理-awk相关的知识,希望对你有一定的参考价值。
- awk是一种编程语言
- 适合文本处理和报表生成
语法格式 awk [option] ‘pattern{action}‘ file awk [参数] ‘条件{动作}‘ 文件
awk命令的参数选项
- -F 指定字段分隔符
- -v 定义或修改一个awk内部的变量
awk命令的常见功能
- 指定分隔符显示某几列
# 直接取出显示出日志文件的url的这一列 awk -F "GET|HTTP" ‘{print $2}‘ access.log
- 通过正则表达式取出你想要的内容
# 分析生产环境中的日志找出谁在破解用户密码 awk ‘$6~/Failed/{print $11}‘ /var/log/secure
- 显示出某个范围内的内容
# 显示文件的20到30行 awk ‘NR==20,NR==30‘ filename
- 通过awk进行统计计算
# 计算总和 awk ‘{sum+=$0}END{print sum}‘ test.txt
- awk数组计算与去重
# 对日志进行统计与计数 awk ‘{array[$1]++}END{for(key in array)print key,array[key]}‘ access.log
指定分隔符显示某几列
# 输出passwd的每一行 awk ‘{print $0}‘ /etc/passwd
# 针对每行以‘:’为分割符,输出第一项 awk -F":" ‘{ print $1 }‘ /etc/passwd
# 针对每行以‘:’为分割符,输出第一项和第二项 awk -F":" ‘{ print $1 $3 }‘ /etc/passwd
# 针对每行以‘:’为分割符,输出第一项和第二项,并格式化输出 awk -F":" ‘{ print $1 " " $3 }‘ /etc/passwd awk -F":" ‘{ print "username: " $1 " uid:" $3 }‘ /etc/passwd
BEGIN和END模块
- 在 awk 开始处理输入文件中的文本之前,执行初始化代码(BEGIN内的代码块)。
- awk 在处理了输入文件中的所有行之后执行END块。
- END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。
赋值运算符
[[email protected] tmp]# awk ‘BEGIN{a=5;a+=5;print a}‘ 10
逻辑运算符
[[email protected] tmp]# awk ‘BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}‘ 0 1
正则运算符
[[email protected] tmp]# awk ‘BEGIN{a="100testaaa";if(a~/100/){print "ok"}}‘ ok [[email protected] tmp]# echo|awk ‘BEGIN{a="100testaaa"}a~/100/{print "ok"}‘ ok
关系运算符
- 其 > < 可以作为字符串比较,也可以用作数值比较,
- 关键看操作数如果是字符串,就会转换为字符串比较。
- 两个都为数字 才转为数值比较。
- 字符串比较:按照ascii码顺序比较。
[[email protected] tmp]# awk ‘BEGIN{a=11;if(a>=9){print "ok"}}‘ ok [[email protected] tmp]# awk ‘BEGIN{a;if(a>=b){print "ok"}}‘ ok
算术运算符
- 所有用作算术运算符进行操作,操作数自动转为数值,
- 所有非数值都变为0。
[[email protected] tmp]# awk ‘BEGIN{a="b";print a++,++a}‘ 0 2 [[email protected] tmp]# awk ‘BEGIN{a="20b4";print a++,++a}‘ 20 22
其他运算符
- ?:三目运算符
[[email protected] tmp]# awk ‘BEGIN{a="b";print a=="b"?"ok":"err"}‘ ok [[email protected] tmp]# awk ‘BEGIN{a="b";print a=="c"?"ok":"err"}‘ err
awk内置变量
变量名 属性 $0 当前记录 $1~$n 当前记录的第n个字段 FS 输入字段分隔符,默认是空格 RS 输入记录分隔符,默认为换行符 NF 当前记录中的字段个数,就是有多少列 NR 已经读出的记录数,就是行号,从1开始 OFS 输出字段分割符,默认是空格 ORS 输出记录分隔符,默认为换行符 字段分隔符 FS
- FS=" +" 一个或多个 Tab 分隔
[[email protected] tmp]# cat tab.txt ww CC IDD [[email protected] tmp]# awk ‘BEGIN{FS=" +"}{print $1,$2,$3}‘ tab.txt ww CC IDD
- FS="[[:space:]+]" 一个或多个空白空格,默认的
[[email protected] tmp]# cat space.txt we are studing awk now! [[email protected] tmp]# awk -F [[:space:]+] ‘{print $1,$2}‘ space.txt we are
- FS="[" ":]+" 以一个或多个空格或:分隔
[[email protected] tmp]# cat hello.txt root:x:0:0:root: /root:/bin/bash [[email protected] tmp]# awk -F [" ":]+ ‘{print $1,$2,$3}‘ hello.txt root x 0
字段数量 NF
- 已":"为分隔符,分隔字段数量NF为8个则输出该行
[[email protected] tmp]# cat hello.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin:888 [[email protected] tmp]# awk -F ":" ‘NF==8{print $0}‘ hello.txt bin:x:1:1:bin:/bin:/sbin/nologin:888
记录数量 NR
- 以一个或多个空格或:分隔得出的结果取第二行
[[email protected] tmp]# ifconfig eth0| awk -F [" ":]+ ‘NR==2{print $4}‘ 192.168.10.10
RS 记录分隔符变量
- 将 FS 设置成" "告诉 awk 每个字段都占据一行。
- 通过将 RS 设置成"",告诉 awk每个地址记录都由空白行分隔。
[[email protected] tmp]# cat recode.txt Jimmy the Weasel 100 Pleasant Drive San Francisco, CA 12345 #此处是空白行 Big Tony 200 Incognito Ave. Suburbia, WA 67890 [[email protected] tmp]# cat awk.txt #!/bin/awk BEGIN { FS=" " RS="" } { print $1 ", " $2 ", " $3 } [[email protected] tmp]# awk -f awk.txt recode.txt Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345 Big Tony, 200 Incognito Ave., Suburbia, WA 67890
OFS 输出字段分隔符
[[email protected] tmp]# cat hello.txt root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin:888 [[email protected] tmp]# awk ‘BEGIN{FS=":"}{print $1","$2","$3}‘ hello.txt root,x,0 bin,x,1 [[email protected] tmp]# awk ‘BEGIN{FS=":";OFS="#"}{print $1,$2,$3}‘ hello.txt root#x#0 bin#x#1
ORS 输出记录分隔符
[[email protected] tmp]# cat recode.txt Jimmy the Weasel 100 Pleasant Drive San Francisco, CA 12345 Big Tony 200 Incognito Ave. Suburbia, WA 67890 [[email protected] tmp]# cat awk.txt #!/bin/awk BEGIN { FS=" " RS="" ORS=" " } { print $1 ", " $2 ", "$3 } [[email protected] tmp]# awk -f awk.txt recode.txt Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345 Big Tony, 200 Incognito Ave., Suburbia, WA 67890
规则表达式
- awk ‘/REG/{action} ‘ file
- /REG/为正则表达式,
- 可以将$0 中,满足条件的记录送入到:action 进行处理
[[email protected] tmp]# awk ‘/root/{print $0}‘ passwd root:x:0:0:root: /root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin [[email protected] tmp]# awk -F : ‘$5~/root/{print $0}‘ passwd root:x:0:0:root: /root:/bin/bash [[email protected] tmp]# ifconfig eth0|awk ‘BEGIN{FS="[[:space:]:]+"} NR==2{print $4}‘ #取出 ip 192.168.10.10 [[email protected] tmp]# ifconfig eth0|awk ‘BEGIN{FS="([[:space:]]|:)+"} NR==2{print $4}‘ #取出 ip 192.168.10.10
布尔表达式
- awk ‘布尔表达式{action}‘ file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。
[[email protected] tmp]# awk -F: ‘$1=="root"{print $0}‘ passwd root:x:0:0:root: /root:/bin/bash [[email protected] tmp]# awk -F: ‘($1=="root")&&($5=="root"){print $0}‘ passwd root:x:0:0:root: /root:/bin/bash
条件语句
{ if ( $1== "foo" ) { if ( $2== "foo" ) { print "uno" } else { print "one" } } elseif ($1== "bar" ) { print "two" } else { print "three" } }
循环结构
do...while循环 { count=1 do { print "I get printed at least once no matter what" } while ( count !=1 ) }
for 循环 { for ( x=1;x<=4;x++ ) { print "iteration", x } }
break和continue
{ x=1 while (1) { if ( x==4 ) { x++ continue } print "iteration", x if ( x>20 ) { break } x++ }
数组
{ cities[1]=”beijing” cities[2]=”shanghai” cities[“three”]=”guangzhou” for( c in cities) { print cities[c] } print cities[1] print cities[“1”] print cities[“three”] }
例子
查看服务器连接状态并汇总 netstat -an|awk ‘/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}‘
统计 web 日志访问流量 要求输出访问次数 请求页面或图片 每个请求的总大小 总访问流量的大小汇总 awk ‘{a[$7]+=$10;++b[$7];total+=$10}END{for(x in a)print b[x],x,a[x]|"sort -rn -k1";print "total size is :"total}‘ access_log a[$7]+=$10表示以第7列为下标的数组($10列为$7列的大小) 把他们大小累加得到$7每次访问的大小 后面的for循环有个取巧的地方,a和b数组的下标相同 所以一条for语句足矣
awk常用函数
函数 说明 gsub( Ere, Repl, [ In ] ) 除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行。 sub( Ere, Repl, [ In ] ) 用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere参数指定的扩展正则表达式的第一个具体值。 sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与 Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录( $0 记录变量)。 index( String1, String2 ) 在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从 1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零)。 length [(String)] 返回 String 参数指定的字符串的长度(字符形式)。如果未给出String 参数,则返回整个记录的长度( $0 记录变量)。 blength [(String)] 返回 String 参数指定的字符串的长度(以字节为单位)。如果未给出String 参数,则返回整个记录的长度( $0 记录变量)。 substr( String, M, [ N ] ) 返回具有 N 参数指定的字符数量子串。子串从 String 参数指定的字符串取得,其字符以 M 参数指定的位置开始。 M 参数指定为将String 参数中的第一个字符作为编号 1。如果未指定 N 参数,则子串的长度将是 M 参数指定的位置到 String 参数的末尾 的长度。 match( String, Ere ) 在 String 参数指定的字符串( Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从 1 开始编号,或如果 Ere 参数不出现,则返回 0 (零)。 RSTART 特殊变量设置为返回值。 RLENGTH特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一)。 split( String, A, [Ere] ) 将 String 参数指定的参数分割为数组元素 A[1], A[2], . . ., A[n],并返回 n 变量的值。此分隔可以通过 Ere 参数指定的扩展正则表达式进行,或用当前字段分隔符( FS 特殊变量)来进行(如果没有给出 Ere参数)。除非上下文指明特定的元素还应具有一个数字值,否则 A 数组中的元素用字符串值来创建。 tolower( String ) 返回 String 参数指定的字符串,字符串中每个大写字符将更改为小写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。 toupper( String ) 返回 String 参数指定的字符串,字符串中每个小写字符将更改为大写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。 sprintf(Format, Expr,Expr, . . . ) 根据 Format 参数指定的 printf 子例程格式字符串来格式化 Expr参数指定的表达式并返回最后生成的字符串。 替换
awk ‘BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}‘ this is a test!test! 在info中查找满足正则表达式,/[0-9]+/用”!”替换,并且替换后的值,赋值给 info未给info值,默认是$0
查找
awk ‘BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}‘ok #未找到,返回 0
匹配查找
awk ‘BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}‘ok #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到
截取
awk ‘BEGIN{info="this is a test2010test!";print substr(info,4,10);}‘s is a tes #从第 4 个 字符开始,截取 10 个长度字符串
分割
awk ‘BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}‘ 44 test 1 this 2 is 3 a #分割info,动态创建数组tA,awk for …in 循环,是一个无序的循环。并不是从数组下标1…n 开始
以上是关于05-Linux文本处理-awk的主要内容,如果未能解决你的问题,请参考以下文章