1.awk 工作原理和基本用法说明
awk
:
Aho, Weinberger, Kernighan
,报告生成器,格式化文本输出,
GNU/Linux
发布的
AWK目前由自 由软件基金会(
FSF
)进行开发和维护,通常也称它为
GNU AWK
有多种版本:
- AWK:原先来源于 AT & T 实验室的的AWK
- NAWK:New awk,AT & T 实验室的AWK的升级版
- GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容
GNU AWK
用户手册文档
https://www.gnu.org/software/gawk/manual/gawk.html
gawk
:模式扫描和处理语言,可以实现下面功能
- 文本处理
- 输出格式化的文本报表
- 执行算数运算
- 执行字符串操作
格式:
awk [options] 'program' var=value file…
awk [options] -f programfile var=value file…
说明:
program
通常是被放在单引号中,并可以由三种部分组成
- BEGIN语句块
- 模式匹配的通用语句块
- END语句块
常见选项:
- -F “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符
- -v var=value 变量赋值
Program
格式:
pattern{action statements;..}
pattern
:决定动作语句何时触发及触发事件,比如:
BEGIN,END,
正则表达式等
action statements
:对数据进行处理,放在
{}
内指明,常见:
print, printf
awk
工作过程

第一步:执行
BEGIN{action;… }
语句块中的语句
第二步:从文件或标准输入
(stdin)
读取一行,然后执行
pattern{ action;… }语句块,它逐行扫描文件, 从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行
END{action;…}
语句块
BEGIN
语句块在
awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打 印输出表格的表头等语句通常可以写在
BEGIN
语句块中
END
语句块在
awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总 都是在
END
语句块中完成,它也是一个可选语句块
pattern
语句块中的通用命令是最重要的部分,也是可选的。如果没有提供
pattern
语句块,则默认执行{ print }
,即打印每一个读取到的行,
awk
读取的每一行都会执行该语句块
分割符、域和记录
- 由分隔符分隔的字段(列column,域field)标记$1,$2...$n称为域标识,$0为所有域,注意:和 shell中变量$符含义不同
- 文件的每一行称为记录record
- 如果省略action,则默认执行 print $0 的操作
常用的
action
分类
- output statements:print,printf
- Expressions:算术,比较表达式等
- Compound statements:组合语句
- Control statements:if, while等
- input statements
awk
控制语句
- { statements;… } 组合语句
- if(condition) {statements;…}
- if(condition) {statements;…} else {statements;…}
- while(conditon) {statments;…}
- do {statements;…} while(condition)
- for(expr1;expr2;expr3) {statements;…}
- break
- continue
- exit
2.动作 print
格式
print item1, item2, ...
说明:
- 逗号分隔符
- 输出item可以字符串,也可是数值;当前记录的字段、变量或awk的表达式
- 如省略item,相当于print $0
- 固定字符符需要用“ ” 引起来,而变量和数字不需要
范例:取出网站访问量最大的前
3
个
IP
[root@VM_0_10_centos logs]# awk '{print $1}' nginx.access.log-20200428|sort |
uniq -c |sort -nr|head -3
5498 122.51.38.20
2161 117.157.173.214
953 211.159.177.120
[root@centos8 ~]#awk '{print $1}' access_log |sort |uniq -c|sort -nr|head
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
2613 172.20.112.14
2267 172.20.0.227
2262 172.20.116.179
2259 172.20.65.65
1565 172.20.0.76
1482 172.20.0.200
1110 172.20.28.145
范例:取出分区利用率
[root@centos8 ~]# df | awk -F"[[:space:]]+|%" '{print $5}'
Use
0
0
1
0
3
19
1
0
范例:取 ifconfig 输出结果中的IP地址
[root@centos8 ~]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.0.85 netmask 255.255.255.0 broadcast 10.0.0.255
inet6 fe80::20c:29ff:fe3d:d1e7 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:3d:d1:e7 txqueuelen 1000 (Ethernet)
RX packets 24590 bytes 25224965 (24.0 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 12793 bytes 4232673 (4.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@centos8 ~]# ifconfig eth0 | sed -n "2p"
inet 10.0.0.85 netmask 255.255.255.0 broadcast 10.0.0.255
[root@centos8 ~]# ifconfig eth0 | sed -n "2p" | awk '{print $2}'
10.0.0.85
[root@centos8 ~]# ifconfig eth0 | awk '/netmask/{print $2}'
10.0.0.85
[root@centos8 ~]# ifconfig eth0 | awk 'NR==2{print $2}'
10.0.0.85
3.awk 变量
awk
中的变量分为:内置和自定义变量
3.1常见的内置变量
- FS:输入字段分隔符,默认为空白字符,功能相当于 -F
范例:
[root@centos8 ~]#awk -v FS=":" '{print $1FS$3}' /etc/passwd |head -n3
root:0
bin:1
daemon:2
- OFS:输出字段分隔符,默认为空白字符
范例:
[root@centos8 ~]#awk -v FS=':' '{print $1,$3,$7}' /etc/passwd|head -n1
root 0 /bin/bash
[root@centos8 ~]#awk -v FS=':' -v OFS=':' '{print $1,$3,$7}'
/etc/passwd|head -n1
root:0:/bin/bash
-
RS :输入记录 record 分隔符,指定输入时的换行符
范例:
awk -v RS=' ' '{print }' /etc/passwd
-
ORS :输出记录分隔符,输出时用指定符号代替换行符
范例:
awk -v RS=' ' -v ORS='###' '{print $0}' /etc/passwd
-
NF:字段数量
范例:
#引用变量时,变量前不需加$
[root@centos8 ~]#awk -F:'{print NF}' /etc/fstab
[root@centos8 ~]#awk -F:'{print $(NF-1)}' /etc/passwd
[root@centos8 ~]#ls /misc/cd/BaseOS/Packages/*.rpm |awk -F"." '{print $(NF-
1)}'|sort |uniq -c
389 i686
208 noarch
1060 x86_64
-
NR :记录的编号
范例:
[root@centos8 ~]#awk '{print NR,$0}' /etc/issue /etc/centos-release
1 \S
2 Kernel \r on an \m
34 CentOS Linux release 8.1.1911 (Core)
-
FNR :各文件分别计数,记录的编号
范例:
awk '{print FNR}' /etc/fstab /etc/inittab
[root@centos8 ~]#awk '{print NR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
34 CentOS Linux release 8.0.1905 (Core)
[root@centos8 script40]#awk '{print FNR,$0}' /etc/issue /etc/redhat-release
1 \S
2 Kernel \r on an \m
31 CentOS Linux release 8.0.1905 (Core)
-
FILENAME :当前文件名
范例:
[root@centos8 ~]#awk '{print FILENAME}' /etc/fstab
[root@centos8 ~]#awk '{print FNR,FILENAME,$0}' /etc/issue /etc/redhat-release
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue
1 /etc/redhat-release CentOS Linux release 8.0.1905 (Core)
-
ARGC :命令行参数的个数
范例:
[root@centos8 ~]#awk '{print ARGC}' /etc/issue /etc/redhat-release
3
3
3
3
[root@centos8 ~]#awk 'BEGIN{print ARGC}' /etc/issue /etc/redhat-release
3
-
ARGV :数组,保存的是命令行所给定的各参数,每一个参数: ARGV[0] , ......
范例:
[root@centos8 ~]#awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release
awk
[root@centos8 ~]#awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release
/etc/issue
[root@centos8 ~]#awk 'BEGIN{print ARGV[2]}' /etc/issue /etc/redhat-release
/etc/redhat-release
[root@centos8 ~]#awk 'BEGIN{print ARGV[3]}' /etc/issue /etc/redhat-release
[root@centos8 ~]#
3.2自定义变量
自定义变量是区分字符大小写的
,
使用下面方式进行赋值
- -v var=value
- 在program中直接定义
范例:
[root@centos8 ~]#awk -v test1=test2="hello,gawk" 'BEGIN{print test1,test2}'
test2=hello,gawk
[root@centos8 ~]#awk -v test1=test2="hello1,gawk"
'BEGIN{test1=test2="hello2,gawk";print test1,test2}'
hello2,gawk hello2,g
4.动作 printf
printf
可以实现格式化输出
格式:
printf “FORMAT”, item1, item2, ...
说明:
- 必须指定FORMAT
- 不会自动换行,需要显式给出换行控制符 \n
- FORMAT中需要分别为后面每个item指定格式符
格式符:与
item
一一对应
%s :显示字符串%d, %i :显示十进制整数%f :显示为浮点数%e, %E :显示科学计数法数值%c :显示字符的 ASCII 码%g, %G :以科学计数法或浮点形式显示数值%u :无符号整数%% :显示 % 自身
修饰符
#[.#] 第一个数字控制显示的宽度;第二个 # 表示小数点后精度,如: %3.1f- 左对齐(默认右对齐) 如: %-15s+ 显示数值的正负符号 如: % + d
范例:
awk -F: '{printf "%s",$1}' /etc/passwd
awk -F: '{printf "%s\n",$1}' /etc/passwd
awk -F: '{printf "%20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s\n",$1}' /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
awk -F: '{printf “Username: %sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %25sUID:%d\n",$1,$3}' /etc/passwd
awk -F: '{printf "Username: %-25sUID:%d\n",$1,$3}'
5.操作符
算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y-x :转换为负数+x :将字符串转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=, +=, -=, *=, /=, %=, ^= , ++, --
范例:
[root@centos8 ~]#awk 'BEGIN{i=0;print i++,i}'
0 1
[root@centos8 ~]#awk 'BEGIN{i=0;print ++i,i}'
1 1
比较操作符:
==, !=, >, >=, <, <=
范例:取奇,偶数行
[root@centos8 ~]#seq 10 | awk 'NR%2==0'
2
4
6
8
10
[root@centos8 ~]#seq 10 | awk 'NR%2==1'
1
3
5
7
9
模式匹配符:
~ 左边是否和右边匹配,包含关系!~ 是否不匹配
范例:
[root@centos8 ~]#awk -F: '$0 ~ /root/{print $1}' /etc/passwd
[root@centos8 ~]#awk -F: '$0 ~ "^root"{print $1}' /etc/passwd
[root@centos8 ~]#awk '$0 !~ /root/' /etc/passwd
[root@centos8 ~]#awk '/root/' /etc/passwd
[root@centos8 ~]#awk -F: '/r/' /etc/passwd
[root@centos8 ~]#awk -F: '$3==0' /etc/passwd
[root@centos8 ~]#df | awk -F"[[:space:]]+|%" '$0 ~ /^\/dev\/sd/{print $5}'
51
92
[root@centos8 ~]#ifconfig eth0 | awk 'NR==2{print $2}'
10.0.0.8
逻辑操作符:
与: && ,并且关系或: || ,或者关系非: ! ,取反
范例:
[root@centos8 ~]#awk 'BEGIN{print !i}'
1
[root@centos8 ~]#awk -v i=10 'BEGIN{print !i}'
0
[root@centos8 ~]#awk -v i=-3 'BEGIN{print !i}'
0
[root@centos8 ~]#awk -v i=0 'BEGIN{print !i}'
1
[root@centos8 ~]#awk -v i=abc 'BEGIN{print !i}'
0
条件表达式(三目表达式)
selector?if-true-expression:if-false-expression
6.模式PATTERN
PATTERN:
根据
pattern
条件,过滤匹配的行,再做处理
- 如果未指定:空模式,匹配每一行
范例
:
[root@centos8 ~]#awk -F: '{print $1,$3}' /etc/passwd
- /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
- relational expression: 关系表达式,结果为“真”才会被处理
真:结果为非0
值,非空字符串
假:结果为空字符串或0
值
- line ranges:行范围
- 不支持直接用行号,但可以使用变量NR间接指定行号
/pat1/,/pat2/ 不支持直接给出数字格式
- BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
7.条件判断 if-else
语法:
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else if(condition3)
{statement3}...... else {statementN}
使用场景:对
awk
取得的整行或某个字段做条件判断
8.条件判断 switch
语法:
switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or
/REGEXP2/: statement2; ...; default: statementn}
9.循环 while
语法:
while (condition) {statement;…}
条件
“
真
”
,进入循环;条件
“
假
”
,退出循环
使用场景:
对一行内的多个字段逐一类似处理时使用
对数组中的各元素逐一处理时使用
10.循环 do-while
语法:
do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
do-while
循环
语法:
do {statement;…}while(condition)
意义:无论真假,至少执行一次循环体
11.循环 for
语法:
for(expr1;expr2;expr3) {statement;…}
常见用法:
for(variable assignment;condition;iteration process) {for-body}
特殊用法:能够遍历数组中的元素
for(var in array) {for-body}
12.continue 和 break
continue
中断本次循环
break
中断整个循环
格式:
continue [n]
break [n]
13.next
next
可以提前结束对本行处理而直接进入下一行处理(
awk
自身循环)
14.数组
awk
的数组为关联数组
格式
array_name[index-expression]
index-expression
- 利用数组,实现 k/v 功能
- 可使用任意字符串;字符串要使用双引号括起来
- 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
- 若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
15.awk 函数
awk 的函数分为内置和自定义函数
官方文档
https://www.gnu.org/software/gawk/manual/gawk.html#Functions
15.1常见内置函数
- 数值处理:
rand():返回0和1之间一个随机数
srand():配合rand() 函数,生成随机数的种子
int():返回整数
- 字符串处理:
length([s]):返回指定字符串的长度
sub(r,s,[t]):对t字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换为s
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,第
一个索引值为1,第二个索引值为2,…
- 可以awk中调用shell命令
system('cmd')
空格是
awk
中的字符串连接符,如果
system
中需要使用
awk
中的变量可以使用空格分隔,或者说
除了
awk
的变量外其他一律用
""
引用起来
- 时间函数
官方文档
:
时间函数
https://www.gnu.org/software/gawk/manual/gawk.html#Time-Functions
systime() 当前时间到1970年1月1日的秒数
strftime() 指定时间格式
15.2 自定义函数
自定义函数格式:
function name ( parameter, parameter, ... ) {
statements
return expression
}
16.awk 脚本
将
awk
程序写成脚本,直接调用或执行
向
awk
脚本传递参数
格式:
awkfile var=value var2=value2... Inputfile
注意:在
BEGIN
过程中不可用。直到首行输入完成以后,变量才可用。可以通过
-v
参数,让
awk在执行 BEGIN
之前得到变量的值。命令行中每一个指定的变量都需要一个
-v
参数