文章目录
1. awk简介
awk 是一种用于处理文本的编程语言工具,是一个报告生成器,拥有强大的文本格式化的能力;同时它支持条件判断、数组、循环等功能,所以,我们也可以把awk理解成一个脚本语言解释器。
awk的创始人是Alfred Aho 、Peter Weinberger 和 Brian Kernighan,它的名字由三个人的姓氏的首字母组成。
awk经过改进生成的新的版本nawk,gawk,现在默认linux系统下日常使用的是gawk,用命令可以查看正在应用的awk的来源(ls -l /bin/awk )。
文本三剑客的特长:
grep 适合单纯的查找或匹配文本
sed 适合编辑匹配到的文本
awk 适合格式化文本,对文本进行较复杂格式处理
awk语法
awk [options] 'Pattern{Action}' file
其中 Pattern{Action} 是使用awk要用的命令(program),要用引号
2. 常用动作之print
awk是逐行处理的.意思就是说,当awk处理一个文本时,会一行一行进行处理,处理完当前行,再处理下一行,awk默认以"换行符"为标记,识别每一行。awk会按照用户指定的分割符去分割当前行,如果没有指定分割符,默认使用空格作为分隔符。
$0
表示显示整行 ,$NF
表示当前行分割后的最后一列(它们均为内置变量)
注意,$NF
和 NF
要表达的意思是不一样的,对于awk来说,$NF
表示最后一个字段,NF表示当前行被分隔符切开以后,一共有几个字段。
也就是说,假如一行文本被空格分成了7段,那么NF
的值就是7,$NF
的值就是$7
, 而$7
表示当前行的第7个字段,也就是最后一列,那么每行的倒数第二列可以写为$(NF-1)
。
awk擅长文本格式化,并且将格式化以后的文本输出,所以awk最常用的动作就是print和printf。
//不使用[options] ,也不指定pattern,使用最简单的action,示例:
[root@master ~]# cat test
123 abc 789 lll
8888 000 222 jkjl 4343
666 999 212
//打印以上文本内容
[root@master ~]# awk '{print}' test
123 abc 789 lll
8888 000 222 jkjl 4343
666 999 212
[root@master ~]# awk '{print $0}' test
123 abc 789 lll
8888 000 222 jkjl 4343
666 999 212
//打印第二列的内容
[root@master ~]# awk '{print $2}' test
abc
000
999
//$2表示将当前行按照分隔符分割后的第2列,不指定分隔符时,默认使用空格作为分隔符。
//表示当前行被分割后的最后一列
[root@master ~]# awk '{print $NF}' test
lll
4343
212
//倒数第二列
[root@master ~]# awk '{print $(NF-1)}' test
789
jkjl
999
//打印多列,用逗号隔开
[root@master ~]# awk '{print $1,$2}' test
123 abc
8888 000
666 999
除了输出文本中的列,我们还能够添加字段,将添加的字段与文件中的列结合起来。可以实现自由组合。
特殊字符要用引号,内置变量不能使用引号。
[root@master ~]# awk '{print $1,$2,"xixi"}' test
123 abc xixi
8888 000 xixi
666 999 xixi
[root@master ~]# awk '{print $1,$2,999}' test
123 abc 999
8888 000 999
666 999 999
[root@master ~]# awk '{print "第一列:"$1,"第二列:"$2}' test
第一列:123 第二列:abc
第一列:8888 第二列:000
第一列:666 第二列:999
3. 特殊模式 BEGIN 和 END
AWK 包含两种特殊的模式:BEGIN 和 END。
- BEGIN 模式指定了处理文本之前需要执行的操作
- END 模式指定了处理完所有行之后所需要执行的操作
[root@master ~]# awk 'BEGIN{print "zzz","222"} {print $1}' test
zzz 222
123
8888
666
//意思是说先打印zzz和222然后在打印$1
[root@master ~]# awk '{print $1}END{print "zzz","222"}' test
123
8888
666
zzz 222
//意思是说先打印$1然后在打印zzz和222
//组合使用
[root@master ~]# awk 'BEGIN{print "zzz","222"}{print $1}END{print "333","444"}' test
zzz 222
123
8888
666
333 444
4. 分隔符
4.1 输入分隔符
- 输入分隔符(field separator),简称FS
- 输入分割符,awk默认以空格为分隔符对每一行进行分割
- 当一个文本中没有空格的时候,可以指定以特殊的字符或者符号作为输入分隔符对文本进行分割
- 特殊字符如
\
>
<
|
等作为输入分隔时必须加引号
[root@minion2 ~]# cat test
123:1p1:bbb
ccc:8p8:999:0000
//指定以:为输入分隔符对文本进行分割
[root@minion2 ~]# awk -F ':' '{print $1,$2}' test
123 1p1
ccc 8p8
//或者不用引号直接紧跟-F后面
[root@minion2 ~]# awk -F: '{print $1,$2}' test
123 1p1
ccc 8p8
//指定以p为输入分隔符对文本进行分割
[root@minion2 ~]# awk -F 'p' '{print $1,$2}' test
123:1 1:bbb
ccc:8 8:999:0000
//特殊字符必须加引号
[root@minion2 ~]# cat test
123>1p1>bbb
ccc>8p8>999>0000
[root@minion2 ~]# awk -F '>' '{print $1,$2}' test
123 1p1
ccc 8p8
同时我们还可以使用-v
选项来指定变量,awk内置变量FS
可以用于指定输入分隔符
[root@minion2 ~]# cat test
123>1p1>bbb
ccc>8p8>999>0000
[root@minion2 ~]# awk -v FS='>' '{print $1,$2}' test
123 1p1
ccc 8p8
4.2 输出分隔符
- 输出分隔符默认也是空格
- awk输出每一列的时候,会使用空格隔开每一列。这个空格,就是awk的默认的输出分隔符。
通过-v
选项来设置内部变量OFS
指定输出分隔符
[root@minion2 ~]# cat test
123>1p1>bbb
ccc>8p8>999>0000
[root@minion2 ~]# awk -v FS='>' -v OFS='#' '{print $1,$2}' test
123#1p1
ccc#8p8
5. 变量
变量名 | 释义 |
---|---|
FS | 输入分隔符,默认为空格 |
OFS | 输出分隔符,默认为空格 |
RS | 输入行记录分隔符,默认是回车换行符 |
ORS | 输出行记录分隔符,默认是回车换行符 |
NF | 当前行的字段个数,即被分割成了几列 |
NR | 当前文本的行号,即有几行 |
FNR | 处理多个文本时,分别记录每个文本的行号 |
FILENAME | 当前文件名 |
ARGC | 命令行参数的个数 |
ARGV | 数组,保存的是命令行所给定的各参数 |
$0 | 当前记录 |
$1 - $n | 当前记录的第n行 |
$NF | 当前记录的最后一列 |
$(NF-n) | 当前记录的倒数NF-n行 |
示例:
5.1 NR
//查看当前文本有几行
[root@localhost ~]# cat test
123>1p1>bbb
ccc>8p8>999>0000
[root@localhost ~]# awk '{print NR}' test
1
2
//NR和NF结合使用
[root@localhost ~]# awk '{print NR,NF}' test
1 1
2 1
//惊奇的发现为啥第一行和第二行都只有一列,因为前文已经说过默认的输入分隔符是空格,这里你没有指定输入分隔符,所以它会把每一行当做一个整体
//我们来指定>号为输入分隔符,看有什么变化
[root@localhost ~]# awk -F'>' '{print NR,NF}' test
1 3
2 4
//指定>号为分隔符以后,第一行被分割成了3列,第二行被分隔成了4列
//为整个文本添加行号
[root@localhost ~]# awk '{print NR,$0}' test
1 123>1p1>bbb
2 ccc>8p8>999>0000
//使用NR取出IP地址
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:18:5b:1c brd ff:ff:ff:ff:ff:ff
inet 192.168.152.131/24 brd 192.168.152.255 scope global dynamic noprefixroute ens33
valid_lft 1597sec preferred_lft 1597sec
inet6 fe80::2a84:f1c4:6a4:1159/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[root@localhost ~]# ip a|awk 'NR==9 {print $2}'|awk -F/ '{print $1}'
192.168.152.131
5.2 FNR
[root@localhost ~]# cat test
123>1p1>bbb
ccc>8p8>999>0000
[root@localhost ~]# cat test1
xixi hehe haha 111
222 888 777 000 9999
[root@localhost ~]# awk '{print FNR,$0}' test test1
1 123>1p1>bbb
2 ccc>8p8>999>0000
1 xixi hehe haha 111
2 222 888 777 000 9999
//上面两个文本的行号分别单独记录
5.3 RS
上面说到RS是输入行分隔符,默认的换行分隔符就是我们平常用的回车换行。
[root@localhost ~]# cat test
123>1p1>bbb
ccc>8p8>999>0000
[root@localhost ~]# awk -v RS='>' '{print NR,$0}' test
1 123
2 1p1
3 bbb
ccc
4 8p8
5 999
6 0000
//这里我们指定>为输入行分隔符,
可以看到它每遇到>就换行,一共有6行。
bbb和ccc被记录成了一行,这是因为它不在以我们熟知的回车换行,
必须要以我们指定的>才会换行
5.4 ORS
上面说到ORS是输出行分隔符,默认也是回车换行
[root@localhost ~]# cat test1
xixi hehe haha 111
222 888 777 000 9999
[root@localhost ~]# awk -v ORS='///' '{print NR,$0}' test1
1 xixi hehe haha 111///2 222 888 777 000 9999///[root@localhost ~]#
我们指定///为输出行分隔符
那么文本将以///换行
你可能会有疑问,它并没有换行啊?
那是因为在你惯性的思维里还是觉得回车才是换行
换行,就是另起一行
而这里所谓的换行就是输出///
//RS和ORS结合使用
[root@localhost ~]# awk -v RS=' ' -v ORS='///' '{print NR,$0}' test1
1 xixi///2 hehe///3 haha///4 111
222///5 888///6 777///7 000///8 9999
如果能理解这个示例的意思,那么一定就学会了使用RS和ORS的用法
5.4 FILENAME
显示当前文件名,这个比较简单,容易理解
[root@localhost ~]# cat test1
xixi hehe haha 111
222 888 777 000 9999
[root@localhost ~]# awk '{print FILENAME,NR,$0}' test1
test1 1 xixi hehe haha 111
test1 2 222 888 777 000 9999
5.5 ARGC和ARGV
- ARGV表示一个数组,命令行直接给,数组的索引都是从0开始的,0是awk本身
- ARGC记录这个数组的个数
[root@localhost ~]# awk 'BEGIN{print "aaa",ARGV[0],ARGV[1],ARGV[2],ARGC}' 11 22
aaa awk 11 22 3
//先输出aaa然后输出ARGV[0],ARGV[1],ARGV[2]
//一共有3个参数
6、printf
看一下printf的输出动作,可以看到 printf 不会输出换行符,默认会将文本输出在一行里面。
[root@localhost ~]# cat test
abc 12345 gg
cde 897 ll vv
[root@localhost ~]# awk '{printf $0}' test
abc 12345 ggcde 897 ll vv[root@localhost ~]#
printf 通过格式替换符可以将文本格式化输出,常见的格式替换符如下:
格式替换符 | 释义 |
---|---|
%s | 字符串 |
%b | 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转义 |
%c | ASCII字符。显示相对应参数的第一个字符 |
%d, %i | 十进制整数 |
%o | 不带正负号的八进制值 |
%u | 不带正负号的十进制值 |
%x | 不带正负号的十六进制值,使用a至f表示10至15 |
%X | 不带正负号的十六进制值,使用A至F表示10至15 |
%x | %% |
转义字符如下:
转义符 | 释义 |
---|---|
\a | 警告字符,通常为ASCII的BEL字符 |
\b | 后退 |
\c | 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略 |
\f | 换页(formfeed) |
\n | 换行 |
\r | 回车(Carriage return) |
\t | 水平制表符 |
\v | 垂直制表符 |
\ | 一个字面上的反斜杠字符,即”\”本身。 |
\ddd | 表示1到3位数八进制值的字符,仅在格式字符串中有效 |
\0ddd | 表示1到3位的八进制值字符 |
在使用 printf 时,指定的格式和打印输出的内容之间要用逗号隔开,而且一个格式对应一个要格式化输出的内容
# 可以看到,虽然你指定了要 $2 ,但是 $2 的内容并没有输出,要想输出,你必须再指定一个格式,格式和输出的内容一一对应
[root@localhost ~]# awk '{printf "%s\n",$1}' test
abc
cde
[root@localhost ~]# awk '{printf "%s\n",$1,$2}' test
abc
cde
[root@localhost ~]# awk '{printf "%s %s\n",$1,$2}' test
abc 12345
cde 897
使用 awk 格式化输出 passwd 文档
[root@localhost ~]# awk -F ":" '{printf "%s %-16s %s %-5s %s %-5s\n","用户名:",$1,"UID:",$3,"GID:",$4}' /etc/passwd
用户名: root UID: 0 GID: 0
用户名: bin UID: 1 GID: 1
用户名: daemon UID: 2 GID: 2
用户名: adm UID: 3 GID: 4
用户名: lp UID: 4 GID: 7
用户名: sync UID: 5 GID: 0
用户名: shutdown UID: 6 GID: 0
用户名: halt UID: 7 GID: 0
用户名: mail UID: 8 GID: 12
用户名: operator UID: 11 GID: 0
用户名: games UID: 12 GID: 100
用户名: ftp UID: 14 GID: 50
用户名: nobody UID: 65534 GID: 65534
用户名: dbus UID: 81 GID: 81
用户名: systemd-coredump UID: 999 GID: 997
用户名: systemd-resolve UID: 193 GID: 193
用户名: tss UID: 59 GID: 59
用户名: polkitd UID: 998 GID: 996
用户名: unbound UID: 997 GID: 994
用户名: sssd UID: 996 GID: 993
用户名: sshd UID: 74 GID: 74
用户名: rngd UID: 995 GID: 992
用户名: nginx UID: 994 GID: 991
7、模式(pattern)
- 关系运算模式
- 空模式
- BEGIN/END模式
- 正则模式
- 行范围模式
模式可以理解为条件,awk 是逐行处理文本的,如果我们指定了条件,只有满足 条件 的行才会被处理,不满足”条件”的行就不会被处理。
[root@localhost ~]# cat test
abc 12345 gg
cde 897 ll vv
rng 90 44 yyds xn
[root@localhost ~]# awk 'NF==5{print $0}' test
rng 90 44 yyds xn
[root@localhost ~]# awk 'NR==1{print $0}' test
abc 12345 gg
7.2 关系运算模式
可以看出上面的示例中,模式用到了关系运算符,我们称之为关系运算模式,awk 支持的关系运算符如下图:
7.3 正则模式
awk ‘/正则表达式/{Action}’
扩展正则加 --posix 选项或者 --re-interval 选项
特殊字符如果代表本身需要转义
[root@localhost ~]# awk '/\/bin\/bash$/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
用awk取出如下文件最少有两个a,最多只有三个a的行
[root@localhost ~]# cat txt
hauyi
haaiuik
haaahkh
haaaauyy
haaaaajklkl
[root@localhost ~]# awk --posix '/ha{2,3}[^a]/{print $0}' txt
haaiuik
haaahkh
7.4 行范围模式
awk ‘/正则1/,/正则2/{Action}’
从匹配到正则1的行开始到匹配到正则2的行结束,不管是正则1还是正则2都以第一次匹配到的行为准
[root@localhost ~]# cat test
abc 12345 gg
cde 897 ll vv
rng 90 44 yyds xn 897
kkl fd 000
000 jkl cdk
[root@localhost ~]# awk '/897/,/000/{print $0}' test
cde 897 ll vv
rng 90 44 yyds xn 897
kkl fd 000
8、动作(Action)
- 控制语句
条件判断,awk 本身就是一门编程语言,所以也是支持 if 语句的,只不过写在了一行
[root@localhost ~]# cat test
abc 12345 gg
cde 897 ll vv
rng 90 44 yyds xn 897
kkl fd 000
000 jkl cdk
[root@localhost ~]# awk '{if(NR>3) print $0}' test
kkl fd 000
000 jkl cdk
[root@localhost ~]# awk '{if(NR==3) {print $1;print $2}}' test
rng
90
if 对应的条件用小括号包起来,if 对应的大括号中有多条语句,if语法中的大括号不能省略,但是,如果 if 对应的大括号中只有一条命令,那么 if 对应的大括号则可以省略。
使用 if...else 语句判断哪些是系统用户,哪些是普通用户
[root@localhost ~]# awk -F ":" '{ if($3 < 500) {print $1,"系统用户"} else {print $1,"普通用户"} }' /etc/passwd
root 系统用户
bin 系统用户
daemon 系统用户
adm 系统用户
lp 系统用户
sync 系统用户
shutdown 系统用户
halt 系统用户
mail 系统用户
operator 系统用户
games 系统用户
ftp 系统用户
nobody 普通用户
dbus 系统用户
systemd-coredump 普通用户
systemd-resolve 系统用户
tss 系统用户
polkitd 普通用户
unbound 普通用户
sssd 普通用户
sshd 系统用户
rngd 普通用户
nginx 普通用户
for 和 while 循环
[root@localhost ~]# awk 'BEGIN{ for( i=1;i<=5;i++) {print i}}'
1
2
3
4
5
[root@localhost ~]# awk 'BEGIN{ i=1;while(i<=5) {print i++}}'
1
2
3
4
5
do…while的示例如下,它与while循环的不同之处在于,
while循环只有当满足条件时才会执行对应语句,而do…while循环则是无论是否满足条件,
都会先执行一遍do对应的代码,然后再判断是否满足while中对应的条件,
满足条件,则执行do对应的代码,如果不满足条件,则不再执行do对应的代码
[root@localhost ~]# awk 'BEGIN{ i=6; do{print "hello wrold";i++} while ( i <= 5 )}'
hello wrold
[root@localhost ~]# awk 'BEGIN{ i=1; do{print "hello wrold";i++} while ( i <= 5 )}'
hello wrold
hello wrold
hello wrold
hello wrold
hello wrold
for循环之continue和break
[root@localhost ~]# awk 'BEGIN{ for(i=1;i<=5;i++) { if(i==2) continue;print i } }'
1
3
4
5
[root@localhost ~]# awk 'BEGIN{ for(i=1;i<=5;i++) { if(i==3) break;print i } }'
1
2
exit的用法
[root@localhost ~]# awk 'BEGIN{print "hello world";print 1;print 2}'
hello world
1
2
[root@localhost ~]# awk 'BEGIN{print "hello world";exit;print 1;print 2}'
hello world
[root@localhost ~]# cat test
abc 12345 gg
cde 897 ll vv
rng 90 44 yyds xn 897
kkl fd 000
000 jkl cdk
[root@localhost ~]# awk 'BEGIN{print "hello world"}{print $0} END {print "over"}' test
hello world
abc 12345 gg
cde 897 ll vv
rng 90 44 yyds xn 897
kkl fd 000
000 jkl cdk
over
[root@localhost ~]# awk 'BEGIN{print "hello world";exit} {print $0} END {print "over"}' test
hello world
over
如果使用了 END 模式,exit 之后的都不会执行,但是 END 后面的内容除外。
没有使用 END 模式,exit之后的内容不会执行,直接退出当前 awk
next的用法,不处理当前行,直接跳到处理下一行
[root@localhost ~]# cat test
abc 12345 gg
cde 897 ll vv
rng 90 44 yyds xn 897
kkl fd 000
000 jkl cdk
[root@localhost ~]# awk '{ if(NR==2) next ; print $0}' test
abc 12345 gg
rng 90 44 yyds xn 897
kkl fd 000
000 jkl cdk
9、数组
在awk中,元素的值可以为空,所以不能根据元素的值是否为空去判断一个元素是否存在;当一个元素不存在于数组时,如果我们直接引用这个不存在的元素,awk会自动创建这个元素,并且默认为这个元素赋值为”空字符串”
[root@localhost ~]# awk 'BEGIN{ subject[0]="语文";subject[1]="数学";subject[2]="英语";subject[3]="历史";subject[4]="";print subject[2] }'
英语
[root@localhost ~]# awk 'BEGIN{ subject[0]="语文";subject[1]="数学";subject[2]="英语";subject[3]="历史";subject[4]="";print subject[4] }'
通过以下语句去判断一个元素是否存在是错误的
[root@localhost ~]# awk 'BEGIN{ subject[0]="语文";subject[1]="数学";subject[2]="英语";subject[3]="历史";subject[4]="";if(subject[4]==0); print "subject数组的第5个元素不存在" }'
subject数组的第5个元素不存在
可以看到当一个元素不存在于数组时,如果我们直接引用这个不存在的元素,awk会自动创建这个元素,并且默认为这个元素赋值为”空字符串”
[root@localhost ~]# awk 'BEGIN{ subject[0]="语文";subject[1]="数学";subject[2]="英语";subject[3]="历史";subject[4]="";if(subject[6]==0); print "subject数组的第7个元素不存在" }'
subject数组的第7个元素不存在
通过以下语法去判断一个元素是否存在
if(下标 in 数组名)
if(!(下标 in 数组名))
[root@localhost ~]# awk 'BEGIN{ subject[0]="语文";subject[1]="数学";subject[2]="英语";subject[3]="历史";subject[4]="";if( 4 in subject ) {print "subject数组的第5个元素存在"} }'
subject数组的第5个元素存在
[root@localhost ~]# awk 'BEGIN{ subject[0]="语文";subject[1]="数学";subject[2]="英语";subject[3]="历史";subject[4]="";if( !(5 in subject) ) {print "subject数组的第6个元素不存在"} }'
subject数组的第6个元素不存在
在awk中,数组的下标不仅可以为数字,可以为任意的字符串
[root@localhost ~]# awk 'BEGIN{ subject["学科1"]="语文";subject["学科2"]="数学";subject["学科3"]="英语";subject["学科4"]="历史";subject["学科5"]=""; print subject["学科1"] }'
语文
使用delete可以删除数组中的元素,也可以删除整个数组
[root@localhost ~]# awk 'BEGIN{ subject["学科1"]="语文";subject["学科2"]="数学";subject["学科3"]="英语";subject["学科4"]="历史";subject["学科5"]=""; print subject["学科1"]; delete subject["学科1"]; print subject["学科1"] }'
语文
#此处是空,是经过删除后的输出
[root@localhost ~]# awk 'BEGIN{ subject["学科1"]="语文";subject["学科2"]="数学";subject["学科3"]="英语";subject["学科4"]="历史";subject["学科5"]=""; print subject["学科1"]; delete subject; print subject["学科3"] }'
语文
#此处是空,是经过删除后的输出
使用 for 循环遍历数组中的每个元素
for循环语法格式1,方式1适用于数组下标都是数字
for(初始化; 布尔表达式; 更新) {
//代码语句
}for循环语法格式2,下标是字符串就可以使用方式2
for(变量 in 数组) {
//代码语句
}
示例中 i 代表元素的下标
[root@localhost ~]# awk 'BEGIN{ subject["学科1"]="语文";subject["学科2"]="数学";subject["学科3"]="英语";subject["学科4"]="历史";subject["学科5"]=""; for( i in subject ){print i,subject[i]} }'
学科1 语文
学科2 数学
学科3 英语
学科4 历史
学科5
数组实际应用场景,在实际工作中,统计某些字符出现的次数,比如,我们想要统计日志中每个IP地址出现了多少次,我们就可以利用数组去统计,在awk中,可以利用数组进行数值运算,参与运算的字符串(下标),字符串将被当做数字0进行运算,空字符串也会当做数字0参与运算
[root@localhost ~]# awk 'BEGIN{ a=1;print a;a++;print a}'
1
2
[root@localhost ~]# awk 'BEGIN{ a="lxr";print a;a++;print a}'
lxr
1
[root@localhost ~]# awk 'BEGIN{ a="lxr";print a;a++;print a;a=a+2;print a }'
lxr
1
3
[root@localhost ~]# awk 'BEGIN{ a="";print a;a++;print a;a=a+2;print a }'
1
3
当一个元素不存在时,这个元素会被赋值空字符串,然后参与运算
[root@localhost ~]# awk 'BEGIN{ print a;a++;print a;a=a+2;print a }'
1
3
统计ip重复了多少次
[root@localhost ~]# cat ip.txt
192.168.249.1
192.168.249.33
192.168.249.123
192.168.249.2
192.168.249.12
192.168.249.14
192.168.249.12
192.168.249.123
192.168.249.133
192.168.249.33
192.168.249.12
192.168.249.12
192.168.249.14
[root@localhost ~]# awk '{ count[$1]++ } END { for( i in count){print i,count[i]} }' ip.txt
192.168.249.123 2
192.168.249.133 1
192.168.249.12 4
192.168.249.1 1
192.168.249.14 2
192.168.249.2 1
192.168.249.33 2
统计人名出现的次数
[root@localhost ~]# cat name
BOb Shelly
Halun BOb Feife Shelly
Even Kobe James
Kobe Pull James
Davies Shelly Halun lxr
[root@localhost ~]# awk '{ for(i=1;i<=NF;i++) { count[$i]++ } } END { for (n in count){print n,count[n]}}' name
James 2
BOb 2
Pull 1
Feife 1
Halun 2
Shelly 3
lxr 1
Kobe 2
Davies 1
Even 1
10、取行取列
取行:NR==1,NR>=1,$3>=1000,$3 ~ /1000/(第三列包含1000,不包含用 !~ 表示)
取列:$1,$NF,$(NF-1)
free | awk '$3>=0 && /Swap/ {print "swap already used!"}'
swap already used!
参考链接如下:
https://www.zsythink.net/archives/tag/awk