awk文本处理
一、前言
(一)、awk简介
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理,数据可以来自标准输入、一个或多个文件,或其它命令的输出,它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具,它在命令行中使用,但更多的是作为脚本来使用;
awk 的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的寻找匹配的特定模式的行,并在这些行上进行你想要的操作,如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理;
awk 分别代表其作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验和GNU的一些扩展。
(二)、awk语法格式
awk [options] 'commands' filenames
awk [options] -f awk-script-file filenames
①、options:
-F 定义输入字段分隔符,默认的分隔符是空格或制表符(tab)
②、command:
BEGIN{} {} END{}
行处理前 行处理 行处理后
# awk 'BEGIN{print 1/2} {print "ok"} END{print "-----------"}' /etc/hosts
0.5
ok
ok
ok
-----------
BEGIN{} 通常用于定义一些变量,例如BEGIN{FS=":";OFS="---"}
③、awk命令格式
awk 'pattern' filename //示例:awk -F: '/root/' /etc/passwd
awk '{action}' filename //示例:awk -F: '{print $1}' /etc/passwd
awk 'pattern {action}' filename //示例:awk -F: '/root/{print $1,$3}' /etc/passwd
//示例:awk 'BEGIN{FS=":"} /root/{print $1,$3}' /etc/passwd
command |awk 'pattern {action}' //示例:df -P| grep '/' |awk '$4 > 25000 {print $4}'
(三)、工作原理
# awk -F: '{print $1,$3}' /etc/passwd
①、awk 使用一行作为输入,并将这一行赋给这内部变量$0,每行也可以成为一个记录,以换行符结束;
②、然后,行被:(默认为空格或制表符)分解成字段(或域),每个字段存储在一编号的变量中,从$1开始,最多达100个字段;
③、awk 如何知道用空格来分割字段的呢?因为有一个内部变量FS来确定字段分割符。初始时,FS赋为空格;
④、awk 打印字段时,将以设置的方法使用print函数打印,awk 在打印字段间加上空格,因为$1,$3之间有一个逗号,逗号比较特殊,它映射为另一个内部变量,称为输出字段分割符OFS,OFS默认为空格;
⑤、awk 输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符将新的字符串分隔成字段并进行处理,该过成将持续到所有行处理完毕;
(四)、记录与字段相关内部变量:man awk
$: //awk变量$0保存当前记录的内容 # awk -F: '{print $0}' /etc/passwd
NR: The total number of input records seen so far. # awk -F: '{print NR, $0}' /etc/passwd /etc/hosts
FNR: The input record number in the current input file # awk -F: '{print FNR, $0}' /etc/passwd /etc/hosts
NF: //保存记录的字段数,$1,$2...$100 # awk -F: '{print $0,NF}' /etc/passwd
FS: //输入字段分隔符,默认空格 # awk -F: '/alice/{print $1, $3}' /etc/passwd
# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd
# awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd
OFS: //输出字段分隔符 # awk -F: '/alice/{print $1,$2,$3,$4}' /etc/passwd
# awk 'BEGIN{FS=":"; OFS="+++"} /^root/{print $1,$2,$3,$4}' passwd
RS The input record separator, by default a newline. # awk -F: 'BEGIN{RS=" "} {print $0}' a.txt
ORS The output record separator, by default a newline. # awk -F: 'BEGIN{ORS=""} {print $0}' passwd
①、区别:
字段分割符:FS OFS 默认空格或制表符
记录分割符:RS ORS 默认换行符
lab1:
[root@linux ~]# awk 'BEGIN{ORS=" "} {print $0}' /etc/passwd //#将文件每一行合并为一行
ORS默认输出一条记录应该回车,加了一个空格
lab2:
[root@linux ~]# head - /etc/passwd > passwd1
[root@linux ~]# cat passwd1
root:x:::root:/root:/bin/bash
[root@linux ~]#
[root@linux ~]# awk 'BEGIN{RS=":"} {print $0}' passwd1
root
x root
/root
/bin/bash [root@linux ~]# awk 'BEGIN{RS=":"} {print $0}' passwd1 |grep -v '^$' > passwd2
(五)、格式化输出:
①、print函数
# date |awk '{print "Month: " $2 "\nYear: " $NF}'
# awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd
# awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd
②、printf函数
# awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd
# awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd %s 字符类型
%d 数值类型
%f 浮点类型
占15字符
- 表示左对齐,默认是右对齐
printf默认不会在行尾自动换行,加\n
(六)、awk 工作模式和动作
任何awk 语句都由模式和动作组成,模式部分决定动作语句何时触发及触发事件,处理即对数据进行的操作。
如果省略模式部分,动作将时刻保持执行状态,模式可以是任何条件语句或复合语句或正则表达式,模式包括两个特殊字段 BEGIN和END ,使用 BEGIN语句设置计数和打印头,BEGIN 语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文本开始执行,END 语句用来在awk 完成文本浏览动作后打印输出文本总数和结尾状态;
①、正则表达式:
匹配记录(整行):
# awk '/^alice/' /etc/passwd
# awk '$0 ~ /^alice/' /etc/passwd
# awk '!/alice/' passwd
# awk '$0 !~ /^alice/' /etc/passwd
匹配字段:匹配操作符(~ !~)
# awk -F: '$1 ~ /^alice/' /etc/passwd
# awk -F: '$NF !~ /bash$/' /etc/passwd
②、比较表达式:
比较表达采用对文本进行比较,只当条件为真,才执行指定的动作,比较表达式使用关系运算符,用于比较数字与字符串;
关系运算符
运算符 含义 示例
< 小于 x<y
<= 小于或等于 x<=y
== 等于 x==y
!= 不等于 x!=y
>= 大于等于 x>=y
> 大于 x>y
# awk -F: '$3 == 0' /etc/passwd
# awk -F: '$3 < 10' /etc/passwd
# awk -F: '$NF == "/bin/bash"' /etc/passwd
# awk -F: '$1 == "alice"' /etc/passwd
# awk -F: '$1 ~ /alic/ ' /etc/passwd
# awk -F: '$1 !~ /alic/ ' /etc/passwd
# df -P | grep '/' |awk '$4 > 25000'
条件表达式:
# awk -F: '$3>300 {print $0}' /etc/passwd
# awk -F: '{ if($3>300) print $0 }' /etc/passwd
# awk -F: '{ if($3>300) {print $0} }' /etc/passwd
# awk -F: '{ if($3>300) {print $3} else{print $1} }' /etc/passwd
算术运算:+ - * / %(模) ^(幂2^3)
可以在模式中执行计算,awk 都将按浮点方式执行算术运算
# awk -F: '$3 * 10 > 500' /etc/passwd
# awk -F: '{ if($3*10>500){print $0} }' /etc/passwd
逻辑操作符和复合模式:
&& 逻辑与 a&&b
|| 逻辑或 a||b
! 逻辑非 !a
# awk -F: '$1~/root/ && $3<=15' /etc/passwd
# awk -F: '$1~/root/ || $3<=15' /etc/passwd
# awk -F: '!($1~/root/ || $3<=15)' /etc/passwd
范围模式:
# awk '/Tom/,/Suzanne/' filename
二、示例
(一)、awk 示例:
# awk '/west/' datafile
# awk '/^north/' datafile
# awk '$3 ~ /^north/' datafile
# awk '/^(no|so)/' datafile
# awk '{print $3,$2}' datafile # awk '{print $3 $2}' datafile
# awk '{print $0}' datafile
# awk '{print "Number of fields: "NF}' datafile
# awk '/northeast/{print $3,$2}' datafile
# awk '/E/' datafile # awk '/^[ns]/{print $1}' datafile
# awk '$5 ~ /\.[7-9]+/' datafile
# awk '$2 !~ /E/{print $1,$2}' datafile
# awk '$3 ~ /^Joel/{print $3 " is a nice boy."}' datafile
# awk '$8 ~ /[0-9][0-9]$/{print $8}' datafile # awk '$4 ~ /Chin$/{print "The price is $" $8 "."}' datafile
# awk '/Tj/{print $0}' datafile
# awk '{print $1}' /etc/passwd
# awk -F: '{print $1}' /etc/passwd
# awk '{print "Number of fields: "NF}' /etc/passwd
# awk -F: '{print "Number of fields: "NF}' /etc/passwd
# awk -F"[ :]" '{print NF}' /etc/passwd
# awk -F"[ :]+" '{print NF}' /etc/passwd
# awk '$7 == 5' datafile
# awk '$2 == "CT" {print $1, $2}' datafile
# awk '$7 != 5' datafile
(二)、awk 进阶:
[root@yang ~]# cat b.txt
yang sheng:is a::good boy!
[root@yang ~]# awk '{print NF}' b.txt [root@yang ~]# awk -F: '{print NF}' b.txt [root@yang ~]# awk -F"[ :]" '{print NF}' b.txt [root@yang ~]# awk -F"[ :]+" '{print NF}' b.txt # awk '$7 < 5 {print $4, $7}' datafile #{if($<){print $,$}}
# awk '$6 > .9 {print $1,$6}' datafile
# awk '$8 <= 17 {print $8}' datafile
# awk '$8 >= 17 {print $8}' datafile
# awk '$8 > 10 && $8 < 17' datafile # awk '$2 == "NW" || $1 ~ /south/ {print $1, $2}' datafile
# awk '!($8 == 13){print $8}' datafile #$ !=
# awk '/southem/{print $5 + 10}' datafile
# awk '/southem/{print $8 + 10}' datafile
# awk '/southem/{print $5 + 10.56}' datafile # awk '/southem/{print $8 - 10}' datafile
# awk '/southem/{print $8 / 2 }' datafile
# awk '/southem/{print $8 / 3 }' datafile
# awk '/southem/{print $8 * 2 }' datafile
# awk '/southem/{print $8 % 2 }' datafile # awk '$3 ~ /^Suan/ {print "Percentage: "$6 + .2 " Volume: " $8}' datafile
# awk '/^western/,/^eastern/' datafile
# awk '{print ($7 > 4 ? "high "$7 : "low "$7)}' datafile //三目运算符 a?b:c 条件?结果1:结果2
# awk '$3 == "Chris" {$3 = "Christian"; print $0}' datafile //赋值运算符
# awk '/Derek/ {$8+=12; print $8}' datafile //$8 += 12等价于$8 = $8 + 12
# awk '{$7%=3; print $7}' datafile //$7 %= 3等价于$7 = $7 % 3
三、awk 脚本编程
(一)、条件判断
①if 语句:
格式
{if(表达式){语句;语句;...}}
awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd
awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd //统计系统用户数
②if...else语句:
格式
{if(表达式){语句;语句;...}else{语句;语句;...}}
awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd
awk -F: '{if($3==0) {count++} else{i++} }' /etc/passwd
awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd
③if...else if...else语句:
格式
{if(表达式1){语句;语句;...} else if (表达式2) {语句;语句;...} else if (表达式3) {语句;语句;...} else {语句;语句;...}}
awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print i; print k; print j}' /etc/passwd
awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户: "j}' /etc/passwd
(二)、循环
①、while:
[root@linux ~]# awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'
[root@linux ~]# awk -F: '/^root/{i=1; while(i<=7){print $i; i++}}' passwd
[root@linux ~]# awk '{i=1; while(i<=NF){print $i; i++}}' /etc/hosts
[root@linux ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd //将每行打印10次
[root@linux ~]# cat b.txt [root@linux ~]# awk '{i=1; while(i<=NF){print $i; i++}}' b.txt //分别打印每行的每列
②、for:
[root@linux ~]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }' //C风格for [root@linux ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd //将每行打印10次
[root@linux ~]# awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd //分别打印每行的每列
root
x root
/root
/bin/bash
bin
x bin
/bin
/sbin/nologin
③、数组:
# awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd
root
# awk -F: '{username[i++]=$1} END{print username[1]}' /etc/passwd
bin
# awk -F: '{username[i++]=$1} END{print username[0]}' /etc/passwd
root
④、数组遍历:
1.按索引遍历
# awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd
# awk -F: '{username[++x]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd
注:变量i是索引
2.按元数个数遍历
# awk -F: '{username[x++]=$1} END{for(i=0;i<x;i++) print i,username[i]}' /etc/passwd
# awk -F: '{username[++x]=$1} END{for(i=1;i<=x;i++) print i,username[i]}' /etc/passwd
四、实例练习
(一)、统计shell
<统计/etc/passwd中各种类型shell的数量>
[root@linux ~]# awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd
(二)、网站访问状态统计
<当前实时状态netstat>
[root@linux ~]# netstat -ant |grep : |awk '{access_stat[$NF]++} END{for(i in access_stat ){print i,access_stat[i]}}'
TIME_WAIT
ESTABLISHED
LISTEN
[root@linux ~]# netstat -ant |grep : |awk '{access_stat[$NF]++} END{for(i in access_stat ){print i,access_stat[i]}}' |sort -k2 -n |head [root@linux ~]# ss -an |grep : |awk '{access_stat[$2]++} END{for(i in access_stat){print i,access_stat[i]}}'
LISTEN
ESTAB
TIME-WAIT [root@linux ~]# ss -an |grep : |awk '{access_stat[$2]++} END{for(i in access_stat){print i,access_stat[i]}}' |sort -k2 -rn
TIME-WAIT
ESTAB
LISTEN
(三)、统计当前访问的每个IP的数量
<当前实时状态netstat,ss>
[root@linux ~]# netstat -ant |grep : |awk -F: '{ip_count[$8]++} END{for(i in ip_count){print i,ip_count[i]} }' |sort
172.16.130.16
172.16.130.33
172.16.130.44
172.16.130.99 [root@linux ~]# ss -an |grep : |awk -F":" '!/LISTEN/{ip_count[$(NF-1)]++} END{for(i in ip_count){print i,ip_count[i]}}' |sort -k2 -rn |head
172.16.160.77
172.16.160.221
172.16.160.17
172.16.160.69
172.16.160.51
172.16.160.49
172.16.160.13
172.16.160.153
172.16.160.79
172.16.160.52
(四)、统计Apache/Nginx日志PV量
<统计Apache/Nginx日志中某一天的PV量,统计日志>
[root@linux log]# grep '22/Mar/2017' cd.mobiletrain.org.log |wc -l
(五)、统计Apache/Nginx日志
<统计Apache/Nginx日志中某一天不同IP的访问量,日志统计>
[root@linux nginx_log]# grep '07/Aug/2012' access.log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |sort -k2 -rn |head
222.130.129.42
123.126.51.94
123.126.68.22
123.114.46.141
61.135.249.218
110.75.173.162
110.75.173.163
110.75.173.161
110.75.173.160
110.75.173.164
[root@linux nginx_log]# grep '07/Aug/2012' access.log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |awk '$2>100' |sort -k2 -rn
222.130.129.42
123.126.51.94
123.126.68.22
123.114.46.141
61.135.249.218
110.75.173.162
110.75.173.163
110.75.173.161
110.75.173.160
110.75.173.164
1.202.218.67
110.75.173.159
203.208.60.80
221.221.207.202
203.208.60.82
203.208.60.81
38.111.147.83
61.135.249.220
183.39.187.86
61.156.142.207
[root@linux log]# awk '/22\/Mar\/2017/{ips[$1]++} END{for(i in ips){print i,ips[i]}}' sz.mobiletrain.org.log |awk '$2>100' |sort -k2 -rn|head180.153.93.
119.147.33.19
119.147.33.26
119.147.33.22
119.147.33.21
101.69.121.35
183.214.128.174
175.6.26.173
27.221.28.174
121.29.54.11
[root@linux log]# awk '/22\/Mar\/2017/{ips[$1]++} END{for(i in ips){if(ips[i]>100){print i,ips[i]}}}' sz.mobiletrain.org.log|sort -k2 -rn|head
180.153.93.44
119.147.33.19
119.147.33.26
119.147.33.22
119.147.33.21
101.69.121.35
183.214.128.174
175.6.26.173
27.221.28.174
121.29.54.11
思路:将需要统计的内容(某一个字段)作为数组的索引++
(六)、awk 函数
统计用户名为4个字符的用户:
[root@linux ~]# awk -F: '$1~/^....$/{count++; print $1} END{print "count is: " count}' /etc/passwd
root
sync
halt
news
uucp
nscd
vcsa
pcap
sshd
dbus
jack
count is:
[root@linux ~]# awk -F: 'length($1)==4{count++; print $1} END{print "count is: "count}' /etc/passwd
root
sync
halt
news
uucp
nscd
vcsa
pcap
sshd
dbus
jack
count is:
(七)、awk 使用外部变量:
①方法一:在双引号的情况下使用
[root@linux ~]# var="bash"
[root@linux ~]# echo "unix script" |awk "gsub(/unix/,\"$var\")"
bash script
②方法二:在单引号的情况下使用
[root@linux ~]# var="bash"
[root@linux ~]# echo "unix script" |awk 'gsub(/unix/,"'"$var"'")'
bash script
[root@linux ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/cl-root .8T 246G .5T % /
tmpfs 24G 20K 24G % /dev/shm
/dev/sda2 1014M 194M 821M % /boot
[root@linux ~]# df -h |awk '{ if(int($5)>5){print $6":"$5} }'
/:%
/boot:%
[root@linux ~]# i=
[root@linux ~]# df -h |awk '{ if(int($5)>'''$i'''){print $6":"$5} }'
/boot:%
方法:awk 参数-v(建议)
[root@linux ~]# echo "unix script" |awk -v var="bash" 'gsub(/unix/,var)'
bash script [root@linux ~]# awk -v user=root -F: '$1 == user' /etc/passwd
root:x:::root:/root:/bin/bash
常用方法:
head 默认为前十;
cat a.txt | awk 'BEGIN{FS="/"}{dict[$3]++}END{for (i in dict)print dict[i],i}' | sort -r | head -
awk文本处理的更多相关文章
- AWK文本处理工具(Linux)
AWK文本处理工具(Linux) PS:刚开始实习,就给了个处理百万级别数据的任务,以前学过SHELL的一些东西sed/awk之类的处理,但是也没有具体的应用,只是在10几行10几列的小数据操作过,所 ...
- Python之路-awk文本处理
作业一:整理博客,内容包含awk.变量.运算符.if多分支 一.awk 1.awk是一个优秀的文本处理工具,多用来处理含有特殊分隔符的内容 常见用法 awk -F: {print $1,$4} 作业 ...
- Shell awk文本处理,shell脚本编写
Shell awk文本处理,shell脚本编写 一:内容包含awk.变量.运算符.if多分支 <a>语法糖: awk [options] 'commands' files option - ...
- awk文本处理知识汇总
参考资料:http://man.linuxde.net/awk http://www.cnblogs.com/chengmo/archive/2013/01/17/2865479.html http: ...
- awk文本分析工具
Usage:awk [option] 'program' file ... awk [option] -f progfile file ... [optin]: -F fs 指定输入分隔符,fs可是字 ...
- Linux下的awk文本分析命令详解
一.简介 awk是一种编程语言,用于在linux/unix下对文本和数据进行处理.数据可以来自标准输入.一个或多个文件,或其它命令的输出.它支持用户自定义函数和动态正则表达式等先进功能,是linux/ ...
- awk 文本处理工具
awk: 强大的文本处理工具,擅长对日志文件进行分析: 不仅用于Linux,也是任何环境中现在的功能最强大的数据处理引擎: 语法说明: awk '{pattern + action}' {filena ...
- Linux - awk 文本处理工具一
AWK AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一:awk经过改进生成的新的版本nawk,gawk,现在默认linux系统下日常使用的是gawk,用命 ...
- sed awk文本处理教程
sed全名叫stream editor,流编辑器,用程序的方式来编辑文本,相当的hacker啊.sed基本上就是玩正则模式匹配,所以,玩sed的人,正则表达式一般都比较强. 把my字符串替换成Hao ...
随机推荐
- System.in 获取键盘输入
此处说明 两种使用System.in获取键盘输入的两种方法,分别是Scanner 和 InputStreamReader. 其中System.in 在System类中的定义如下: package co ...
- 跟我学SpringCloud | 第七篇:Spring Cloud Config 配置中心高可用和refresh
SpringCloud系列教程 | 第七篇:Spring Cloud Config 配置中心高可用和refresh Springboot: 2.1.6.RELEASE SpringCloud: Gre ...
- 多语言应用性能监控系统:Elastic APM
▶ 概述 Elastic APM 是基于 Elastic Stack 构建的应用性能监控系统.通过 Elastic APM 可以监控应用程序,收集有关请求的响应时间.数据库查询.高速缓存调用.外部 H ...
- IO侦探:多进程写ceph-fuse单文件性能瓶颈侦查
近期接到ceph用户报案,说是多进程direct写ceph-fuse的单个文件,性能很低,几乎与单进程direct写文件的性能一样.关乎民生,刻不容缓,笔者立即展开侦查工作~ 一.复现案情,寻踪追记 ...
- gulp使用详情 及 3.0到4.0的坑
项目的所有依赖都可以安装,每个都有详细的注释. const gulp = require('gulp'); const sass = require('gulp-sass'); const brows ...
- 常用的方法论-AAR
- django基础知识之管理静态文件css,js,images:
管理静态文件 项目中的CSS.图片.js都是静态文件 配置静态文件 在settings 文件中定义静态内容 STATIC_URL = '/static/' STATICFILES_DIRS = [ o ...
- 嵊州D2T1 “我只是来打个电话”
嵊州D2T1 “我只是来打个电话” 精神病院有一个这样的测试. 给出一个正整数集合,集合中的数各不相同,然后要求病人回答: 其中有多少个数,恰好等于集合中另外两个(不同的)数之和? 回答正确的人,即可 ...
- 洛谷P1003 铺地毯 noip2011提高组day1T1
洛谷P1003 铺地毯 noip2011提高组day1T1 洛谷原题 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n ...
- 作者联系方式D1
欢迎大伙投稿,审核通过免费发布. 奥特曼超人 KARL-Dujinyang QQ: 309933706 QQ: 1875125470 工作时间都会在线. 偶尔博客,不过有问题可以加Q来找我讨论 ...