awk简介

awk功能与sed相似,都是用来进行文本处理的。awk可以自动地搜索输入文件,并把每一个输入行切分成字段。许多工作都是自动完成的,例如读取每个输入行、字段分割。

awk工作原理

awk一次从文本内容中读取一行文本,按输入分隔符进行切,也可以使用-F选项指定分隔符,切成多个组成部分,将每段内容直接保存在内建的变量中$1,$2,$3....$NF(最后一列),引用指定的变量,可以显示指定断,或者多个断。如果需要显示全部的,需要使用$0来引用。可以对单个片断进行判断,也可以对所有断进行循环判断。其默认分隔符为空格

基础应用示例

选项:

-F 指明输入时用到的字段分隔符

-v var=value: 自定义变量

awk最常用的格式为:awk [options] 'pattern{action}' file

最常用的action是:print

一个示例:

[root@yufu ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 4.8G 1.6G 3.0G 35% /
/dev/sda1 190M 37M 144M 21% /boot
/dev/sda3 2.8G 1.1G 1.6G 39% /home

处理:awk可以处理多列

[root@yufu ~]# df -h | awk '{print $1}'
Filesystem
/dev/sda2
/dev/sda1
/dev/sda3
[root@yufu ~]# df -h | awk '{print $1,$5}'
Filesystem Use%
/dev/sda2 35%
/dev/sda1 21%
/dev/sda3 39%

$0与$NF,NF,$NF-1

$0整行输出

[root@yufu ~]# df -h | awk '{print $0}'
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 4.8G 1.6G 3.0G 35% /
/dev/sda1 190M 37M 144M 21% /boot
/dev/sda3 2.8G 1.1G 1.6G 39% /home

$NF的尾列输出

[root@yufu ~]# df -h | awk '{print $NF}'
on
/
/boot
/home

NF是统计每一行的总列数

[root@yufu ~]# df -h | awk '{print NF}'
7
6
6
6

$(NF-1)倒数第二列

[root@yufu ~]# df -h | awk '{print $1,$(NF-1)}'
Filesystem Mounted
/dev/sda2 35%
/dev/sda1 21%
/dev/sda3 39%

自定义插入字符

在输出文本列中,还可以添加自己要插入的内容

默认输出的字段之间间隙比较小,可以在字段键插入tab键分开距离

[root@yufu ~]# df -h | awk  '{print $1"\t"$2}'
Filesystem Size
/dev/sda2 4.8G
/dev/sda1 190M
/dev/sda3 2.8G

也可以是输出内容更具可读性

[root@yufu ~]# df -h | awk  '{print $1" 磁盘大小:"$2}'
Filesystem 磁盘大小:Size
/dev/sda2 磁盘大小:4.8G
/dev/sda1 磁盘大小:190M
/dev/sda3 磁盘大小:2.8G

awk两种特殊模式

BEGIN和END是awk的两种特殊模式

BEGIN模式指定了处理文件前要执行的操作

END模式是指处理完所有行后要执行的操作

下面用一个示例来看:在磁盘使用率上加上一行标题,最后一行加上end标识

[root@yufu ~]# df -h | awk 'BEGIN{print "this is disk usage status:"} {print $1"\t"$5}'
this is disk usage status:
Filesystem Use%
/dev/sda2 35%
/dev/sda1 21%
/dev/sda3 39%
[root@yufu ~]# df -h | awk 'BEGIN{print "this is disk usage status:"} {print $1"\t"$5} END{print "end"}'
this is disk usage status:
Filesystem Use%
/dev/sda2 35%
/dev/sda1 21%
/dev/sda3 39%
end

awk分隔符

awk的分隔符分两种:“输入分隔符”和“输出分隔符”:

输入分隔符 : 简称 FS;默认的输入分隔符是空格,awk默认以空格为分隔符将文件进行列的分割。

输出分隔符 简称OFS;awk将文本切割处理后输出在屏幕上,以什么字符作为字段的分隔符?默认也是为空白字符最为输出分隔符。

在处理文本时,如果文本中没有空白字符那怎么进行分割?这时需要使用输入分隔符指定其他的字符作为分隔符进行切片处理,其实这里的 FS和上面示例中使用的-F作用是一样的,都是指定输入的分割符,同时,FS定义的分隔符可以在Action中进行引用作为输出时插入的内容

使用FS指定分隔符

[root@yufu ~]# awk -v FS=':' '{print $1,$3}' /etc/passwd | head -n 3
root 0
bin 1
daemon 2
[root@yufu ~]# awk -v FS=':' '{print $1FS$3}' /etc/passwd | head -n 3
root:0
bin:1
daemon:2

awk处理输出的内容默认是以空白字符作为列的分隔符,如果要指定输出内容的分割符可以使用OFS来指定,一个列子对比

[root@yufu ~]# df -h | awk '{print $1,$5}'
Filesystem Use%
/dev/sda2 35%
/dev/sda1 21%
/dev/sda3 39%
[root@yufu ~]# df -h | awk -v OFS=------ '{print $1,$5}'
Filesystem------Use%
/dev/sda2------35%
/dev/sda1------21%
/dev/sda3------39%

awk变量

内置变量

在上面的示例中已经使用到了变量,awk变量分为“内置变量”和“自定义变量”,示例中用到的NF、FS、OFS等就是awk的自定义变量,内置变量是awk预置好的,而自定义变量需要用户自己定义。

awk常用的内置变量如下:
FS:输入字段分隔符,默认为空白字符
OFS:输出字段分隔符,默认为空白字符
RS:输入记录的分隔符(换行符),指定输入时的换行符
NF:当前行的字段数(被分割成的列数),$NF 为最后一列,两者不同
NR:行号,当前处理文本的行号(也可以使用NR指定输出哪一行)
FNR:各文件分别计数的行号
FILENAME:当前文件名
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行所给定的各个参数

上面已经写了FS和OFS的使用,接着看看RS,RS直白理解就是定义文本内容中以什么作为行的分隔符,有时候会用到这种方式定义行的分割

一个列子:fstab文件以 双引号 作为行的分隔符

[root@yufu opt]# cat /etc/fstab
UUID="6ec772b7-9efb-46d0-80a5-4deaf6d6efe0" /boot ext4 defaults 0 0
UUID="96cb6b8f-c3da-41d1-a063-cfd0e8177085" / ext4 defaults 0 0
UUID="6c323417-2b44-48fd-a4b3-074085b5fe95" /home ext4 defaults 0 0
UUID="fc02879d-56bb-4153-8fa9-c21aa9af8b19" swap swap defaults 0 0
[root@yufu opt]# cat /etc/fstab | awk -v RS='"' '{print $1}'
UUID=
6ec772b7-9efb-46d0-80a5-4deaf6d6efe0
/boot
96cb6b8f-c3da-41d1-a063-cfd0e8177085
/
6c323417-2b44-48fd-a4b3-074085b5fe95
/home
fc02879d-56bb-4153-8fa9-c21aa9af8b19
swap

ORS指定输出分隔符

OFS可以指定输出时字段间用什么样的字符作为分隔符。默认为空格,这个功能与OFS作用差不多,个人感觉没有OFS好用。两个例子对比

ORS输出分割(乱遭遭的,看不懂)

[root@yufu opt]# df -h | awk -v ORS='----' '{print $1,$2}'
Filesystem Size----/dev/sda2 4.8G----/dev/sda1 190M----/dev/sda3 2.8G

OFS输出分割

[root@yufu opt]# df -h | awk -v OFS=---- '{print $1,$2}'
Filesystem----Size
/dev/sda2----4.8G
/dev/sda1----190M
/dev/sda3----2.8G

NF和$NF的用法

稍不注意会被这两个给搞混了,NF是统计一行中的列数,而$NF是取一行中的最后一列

一个例子对比

[root@yufu opt]# cat /etc/fstab
UUID="6ec772b7-9efb-46d0-80a5-4deaf6d6efe0" /boot ext4 defaults 0 0
UUID="96cb6b8f-c3da-41d1-a063-cfd0e8177085" / ext4 defaults 0 0
UUID="6c323417-2b44-48fd-a4b3-074085b5fe95" /home ext4 defaults 0 0
UUID="fc02879d-56bb-4153-8fa9-c21aa9af8b19" swap swap defaults 0 0
[root@yufu opt]# awk '{print NF,$NF}' /etc/fstab
6 0
6 0
6 0
6 0

每行以空格分割,一个6列。最后一列是0

NR行号处理

NR可以用来显示处理行的行号,也可以用来匹配指定行的内容

示例

[root@yufu opt]# df -h | awk '{print NR,$0}'
1 Filesystem Size Used Avail Use% Mounted on
2 /dev/sda2 4.8G 1.6G 3.0G 36% /
3 /dev/sda1 190M 37M 144M 21% /boot
4 /dev/sda3 2.8G 1.1G 1.6G 39% /home

指定行号处理

[root@yufu opt]# df -h | awk 'NR==2 {print $1,$5}'
/dev/sda2 36%

指定行号输出

[root@yufu opt]# df -h | awk 'NR==2'
/dev/sda2 4.8G 1.6G 3.0G 36% /

FNR:用于分别显示两个文件行号

[root@yufu opt]# awk '{print FNR,$0}' fi.txt fr.txt
1 hfjg
2 jsklyhfg
3 kifg
1 jkdfgufgjk
2 sdfg

ARGV内置变量表示的是一个数组,这个数组中保存的是命令行所给定的参数,数组的下标从0开始

一个列子

[root@yufu opt]# awk 'BEGIN{print "aaa",ARGV[1]}' fi.txt fr.txt
aaa fi.txt
[root@yufu opt]# awk 'BEGIN{print "aaa",ARGV[0]}' fi.txt fr.txt
aaa awk
[root@yufu opt]# awk 'BEGIN{print "aaa",ARGV[2]}' fi.txt fr.txt
aaa fr.txt

自定义变量

自定义变量容易理解,就是我们自己定义的变量,定义的方法:

自定义变量: -v varname=value (变量名区分大小写)

[root@yufu opt]# awk -v myvar="gudaoyufu" 'BEGIN{print myvar}'
gudaoyufu

或者

[root@yufu opt]# awk  'BEGIN{myvar="gudaoyufu";print myvar}'
gudaoyufu

awk格式化输出

在输出时可以是内容一一些特定的格式输出,格式化输出则需要使用printf来指定,功能与print相似,只是这个可以支持格式化输出

格式化输出:printf “FORMAT” , item1, item2, ...

(1) 必须指定FORMAT

(2) 不会自动换行,需要显式给出换行控制符,\n

(3) FORMAT中需要分别为后面每个item指定格式符

格式符:与item一一对应

%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%: 显示%自身

修饰符:

#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f

-: 左对齐(默认右对齐) %-15s
+:显示数值的正负符号 %+d

printf示例

[root@yufu opt]# awk -F : '{printf "%-15s %-10d\n",$1,$3}' /etc/passwd | head -n 4
root 0
bin 1
daemon 2
adm 3
[root@yufu opt]# awk -F : '{printf "-15s UID:%-10d\n",$1,$31}' /etc/passwd | head -n 4
root UID:0
bin UID:1
daemon UID:2
adm UID:3

awk运算操作

上面有个示例:

[root@yufu opt]# awk 'NR==2 {print $1}' /etc/fstab
UUID="96cb6b8f-c3da-41d1-a063-cfd0e8177085"

这个就使用到了运算符,“NR==2”,获取一个行并做处理,awk支持多种运算处理

算术操作符:

x+y, x-y, x*y, x/y, x^y, x%y
-x: 转换为负数
+x: 转换为数值

字符串操作符:没有符号的操作符,字符串连接

赋值操作符:

=, +=, -=, *=, /=, %=, ^=
++, --

比较操作符:

==, !=, >, >=, <, <=

逻辑操作符:与&&,或||,非!

简单示例

[root@yufu opt]# awk -F :  '$3>=600 {print $1,$3}' /etc/passwd
suzhou 600
yufu 601
guoguo 602
user2 604
user3 605
user4 606
user5 607
user6 608
user7 609
user8 610
user9 611
user10 612
[root@yufu opt]# awk -F :  '$3 <100 || $3 >=600 {print $1,$3}' /etc/passwd
root 0
bin 1
dbus 81
vcsa 69
postfix 89
sshd 74
oprofile 16
... ...
suzhou 600
yufu 601
guoguo 602

匹配磁盘使用情况

[root@yufu opt]# df -h|awk -F% '/^\/dev/{print $1}'|awk '$NF>=30{print $1,$5}'
/dev/sda2 36
/dev/sda3 39

awk的PATTERN匹配

PATTERN:根据pattern条件,过滤匹配的行,再做处理,PATTERN中可以使用正则表达式来进行文本匹配

,例如,匹配passwd中以user开头的用户

[root@yufu opt]# awk '/^user/{print $0}' /etc/passwd
user2:x:604:604::/home/user2:/bin/bash
user3:x:605:605::/home/user3:/bin/bash
user4:x:606:606::/home/user4:/bin/bash
user5:x:607:607::/home/user5:/bin/bash
user6:x:608:608::/home/user6:/bin/bash
user7:x:609:609::/home/user7:/bin/bash
user8:x:610:610::/home/user8:/bin/bash
user9:x:611:611::/home/user9:/bin/bash
user10:x:612:612::/home/user10:/bin/bash

上面这个功能实现了grep的匹配功能,但它的使用与grep还是有些区别的:

grep "正则表达式" /etc/passwd

awk '/正则表达式/ {print $0}' /etc/passwd

在awk使用正则表达式时特殊字符要使用转义符;如下:

[root@yufu opt]# awk '/\/bin\/bash$/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
suzhou:x:600:600::/home/feng:/bin/bash
tomcat:x:501:501::/home/tomcat:/bin/bash
yufu:x:601:601::/home/yufu:/bin/bash
guoguo:x:602:602::/home/guoguo:/bin/bash
user2:x:604:604::/home/user2:/bin/bash
... ...

结构控制语句

在awk中我们同样可以if这样的语法进行条件判断,只是在awk中使用if判断条件是在一行中完成,下面的一个示例:查看使用率超过30的分区

[root@yufu ~]# df -h | awk  '/^\/dev\/sd/{if ($5>=30){print $1,$5}}'
/dev/sda2 36%
/dev/sda3 39%

如果判断条件不成立则进行下面的动作:

[root@yufu ~]# df -h | awk  '/^\/dev\/sd/{if ($5>=50){print $1,$5}else{print $1,$5}}'
/dev/sda2 36%
/dev/sda1 21%
/dev/sda3 39%

awk数组使用

数组的格式:

name[0]="xiaoming"

name[1]="laowang"

上列中name为数组名,[0],[1]为元素下标 ,“小明”为数组元素

定义并打印一个简单的数组

[root@yufu ~]# awk 'BEGIN {a[0]="gudao";a[1]="yufu";print a[0],a[1]}'
gudao yufu

打印数的下标

[root@yufu ~]# awk 'BEGIN {a[0]="gudao";a[1]="yufu";for (i in a){print i}}'
0
1

把数组的下标和元素一起打印

[root@yufu ~]# awk 'BEGIN {a[0]="gudao";a[1]="yufu";for (i in a){print i, a[1]}}'
0 yufu
1 yufu

数组遍历

数组遍历需要使用for循环来配合处理,下面以一个示例看看awk的数组遍历的使用:

示例:一个web日志文件有60多万条的记录,怎样统计日志里每个ip的访问次数呢?

[root@yufu ~]# head access_log
192.168.30.6 - - [14/May/2018:14:21:41 +0800] "GET / HTTP/1.1" 200 18 "-" "curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.21 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2"

方法一:

[root@yufu ~]# cat access_log | awk '{print $1}' | sort |uniq -c | sort -nr
295764 172.20.109.251
170000 172.20.109.233
100000 172.20.101.240
39243 172.20.111.90
16000 172.20.109.164
8000 172.20.102.79
6062 172.20.111.9
6000 172.20.103.69
4031 172.20.101.23
4014 192.168.30.6
4000 172.20.1.24
2056 172.20.111.65
2020 172.20.111.164
2002 172.20.110.34
2000 172.20.111.162
400 172.20.75.66
58 ::1
10 192.168.30.1

方法二:用AWK数组遍历来统计

[root@yufu ~]# awk '{num[$1]++}END{for(i in num){print i,num[i]}}' access_log | sort -nr -k2
172.20.109.251 295764
172.20.109.233 170000
172.20.101.240 100000
172.20.111.90 39243
172.20.109.164 16000
172.20.102.79 8000
172.20.111.9 6062
172.20.103.69 6000
172.20.101.23 4031
192.168.30.6 4014
172.20.1.24 4000
172.20.111.65 2056
172.20.111.164 2020
172.20.110.34 2002
172.20.111.162 2000
172.20.75.66 400
::1 58
192.168.30.1 10

理解上面的例子:

awk中使用的num[$1]++ :数组中将日志文件的第一列作为数组num的下标,awk在读取第一行时会读取到这个数组,此时数组是这样的:num[172.20.109.251]++,由于后边的++运算符,awk会将数字0自动赋值给num[172.20.109.251]然后再做++运算。

此时num[172.20.109.251]做++,也就是0+1=1

当在读到第二个172.20.109.251时,此时num[172.20.109.251]的值已经为1,再做一次—++运算就是1+1得到的值为2,就这样以此类推

最后的++运算的值是多少,也就意味着172.20.109.251这个ip被运算了多少次,也就意味着这个地址出现了多少次。

最后通过for循环把num数组的下标(ip)和出现的次数都打印出来

同样,可以利用awk数组统计tcp的连接数:

[root@centos ~]# netstat -ant | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,"\t"state[i]}}'
TIME_WAIT 19
CLOSE_WAIT 1
ESTABLISHED 5
LISTEN 11

还可以统计当前系的80端口的连接数与远程连接的ip

[root@web ~]# netstat -nat | grep "ESTABLISHED" | awk '/^tcp/{state[$(NF-2)]++}END{for(a in state){print a "  " state[a]}}' | grep ':80'
192.168.19.47:80 4

文本处理工具-AWK的更多相关文章

  1. 文本处理工具awk

    目录 gawk:模式扫描和处理语言 awk语言 awk工作原理 print awk变量 自定义变量 printf命令 awk操作符 awk的条件判断 awk的循环 awk的数组 awk的函数 awk调 ...

  2. linux 文本分析工具---awk命令(7/1)

    awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各 ...

  3. 文本分析工具awk简单示例

    先创建一个文件:vim hi 取第2个字段和第3个字段: awk '{print $2,$3}' hi     注意{}中的,逗号会在输出的时候转变为空格 加入字符说明: 显示整行: 指定字段分隔符: ...

  4. AWK文本处理工具(Linux)

    AWK文本处理工具(Linux) PS:刚开始实习,就给了个处理百万级别数据的任务,以前学过SHELL的一些东西sed/awk之类的处理,但是也没有具体的应用,只是在10几行10几列的小数据操作过,所 ...

  5. Pyp 替代sed,awk的文本处理工具

    Linux上文本处理工具虽不少,像cut,tr,join,split,paste,sort,uniq,sed,awk这些经典工具让人眼花缭乱,而且都太老了,使用方法都不太人性化,尤其awk,语法简直反 ...

  6. 三大文本处理工具grep、sed及awk的简单介绍

    grep.sed和awk都是文本处理工具,虽然都是文本处理工具单却都有各自的优缺点,一种文本处理命令是不能被另一个完全替换的,否则也不会出现三个文本处理命令了.只不过,相比较而言,sed和awk功能更 ...

  7. Unix文本处理工具之awk

    Unix命令行下输入的命令是文本,输出也都是文本.因此,掌握Unix文本处理工具是很重要的一种能力.awk是Unix常用的文本处理工具中的一种,它是以其发明者(Aho,Weinberger和Kerni ...

  8. 【Linux】 字符串和文本处理工具 grep & sed & awk

    Linux字符串&文本处理工具 因为用linux的时候主要用到的还是字符交互界面,所以对字符串的处理变得十分重要.这篇介绍三个常用的字符串处理工具,包括grep,sed和awk ■ grep ...

  9. Linux的文本处理工具浅谈-awk sed grep

    Linux的文本处理工具浅谈 awk   老大 [功能说明] 用于文本处理的语言(取行,过滤),支持正则 NR代表行数,$n取某一列,$NF最后一列 NR==20,NR==30 从20行到30行 FS ...

随机推荐

  1. pat1090. Highest Price in Supply Chain (25)

    1090. Highest Price in Supply Chain (25) 时间限制 200 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 C ...

  2. C#序列化结构体

    在将对象或结构体序列化成二进制数据流时,我们通常都会使用 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter 类来实现, 但是 ...

  3. spring aop xml中配置实例

    http://blog.csdn.net/wangpeng047/article/details/8560694

  4. 微信小程序实战篇:基于wxcharts.js绘制移动报表

    前言 微信小程序图表插件(wx-charts)是基于canvas绘制,体积小巧,支持图表类型饼图.线图.柱状图 .区域图等图表图形绘制,目前wx-charts是微信小程序图表插件中比较强大好使的一个. ...

  5. node-sass 安装报错解决办法

    npm install安装node-sass时出现以下问题: Cannot download https://github.com/sass/node-sass/releases/download/v ...

  6. Android中快速实现自定义字体!

    前言:我们都知道,Android中默认的字体是黑体,而大多数app也都是使用的这种字体,但我们发现,大多数app中,个别地方字体非常好看,例如app的标题栏,菜单栏等地方,那他们是怎么做到的呢?有两种 ...

  7. SpringCloud的学习记录(5)

    这一章节讲如何使用ribbon和hystrix. 在我们生成的Demo项目上右键点击New->Module->spring Initializr, 然后next, 填写Group和Arti ...

  8. Unity3D 调用Android与IOS的剪贴板

    Unity3D剪贴板 最近遇到一个需要调用Android与IOS设备本身剪贴板的需求,就是在Unity中,要将文本复制到设备本身的剪贴板中,然后在其他应用程序中都能粘贴. 最开始在网上查到的方式是使用 ...

  9. NFS笔记(二)NFS服务器配置实例

    一.NFS服务器配置实例实验拓扑 二.实验要求及环境 2.1实验环境 NFS服务器 IP:192.168.8.5环境:[root@server7 ~]# uname -aLinux server7.c ...

  10. WannaCry勒索病毒卷土重来:日本本田工厂被迫关闭

    6月22日消息,前阵子WannaCry勒索病毒席卷全球,世界各地网络遭到攻击.日前,偃旗息鼓了一阵的WannaCry勒索病毒又重回人们视线,迫使一家汽车厂在日本关闭. 路透社报道,本田Sayama工厂 ...