awk原理
awk
是把文件逐行读入,以空格为默认分隔符将每行切片,切开的部分叫做“域”,然周再对于每个域进行各种分析处理,如:去重、排序、执行计算、报表等等。
awk语法
awk 'pattern + {action}' {filename}
pattern
:awk
在数据中查找的内容
action
:匹配内容时所执行的一系列命令
filename
:要处理的文件
awk选项
-v
:定义变量-f
:指定awk脚本-F
:指定分隔符,若有多个分隔符,使用[.|>/]
中括号,[]
内可写正则表达式
awk调用方法
1、命令行
awk [-F 分隔符] 'commands' input-files
2、shell
脚本
#!/bin/awk
3、awk
编程文件
awk -f awk-script-file input-files
awk案例
1、显示linux
下最后登陆的5
个账号名
last -n 5 | awk '{print $1}'
工作流程:
从标准输出读入有\n
换行符分割的一条记录,然后将该记录按指定的域分隔符划分域,填充域。
$0
:表示所有域
$1
:第一个域
$2
:第二个域
$NF
:最后一个域
NR
:已读记录数(当处理两个文件时,会从新计数)
FNR
:已读记录数(当处理两个文件时,不会从新计数)
FILENAME
:文件名
2、显示用户名和登陆shell
,用tab
分割,第一行显示name shell
,最后一行显示end!
awk -F ":" 'BEGIN {print "name" "\t" "shell"} {print $1,$NF} END {print "end!"}' /etc/passwd
工作流程:
先执行BEGIN
;然后读取文件,执行action
;最后执行END
3、搜索有root
关键字的所有行,输出对应的shell
awk -F ":" '/root/ {print $1,$NF}' /etc/passwd
awk -F: '/^.*root.*$ {print $1,$NF}' /etc/passwd
这种就是pattern
的使用案例,匹配pattern (root)
的行才会执行action
。若没有指定action
,默认输出每行的内容。
其中可使用printf
代替print
,可定义更加复杂的输出格式!
4、使用awk
对一个文件的第3
列进行去重
awk -F: '!a[$3]++ {print $3}' /etc/passwd
处理流程:
- 在awk中,对于未初始化的数组变量,在进行数值运算时,会赋予初始值
0
,因此a[$3]=0
; ++
运算符的特征是先取值,后加1
,因此pattern
等价于!0
0
为假,!
取反,因此pattern
最后结果为1
,就相当于if(1)
,pattern
匹配成功,输出当前记录(执行的action
)- 最后
a[$3]
加1
- 当执行到下一回合,遇到重复的
$3
内容,此时a[$3]=1
(因为上一步加1
),取反为0
,指为假,所以就不会输出了
5、统计当前文件夹下的文件大小总和,用MB
展示
find ./ -type f | ls -l | awk 'BEGIN {size=0} {size += $5} END {print size / 1024 / 1024 "MB"}'
自定义变量size
6、统计当前文件夹下文件大小总和,排除4096
大小的文件
ls -l | awk 'BEGIN {size=0} {if(size != 4096) {size += $5;}} END {print size / 2014 / 1024 "MB"}'
7、循环输出用户名
awk -F: 'BEGIN {count=0} {name[count]=$1; count++} END {for(i=0; i<NR; i++) print i, name[i]}' /etc/passwd
8、输出文件中第2
列包含th
的行,不区分大小写
awk 'BEGIN {IGNORECASE=1} $2~/th/' filename
IGNORECASE=1
:忽略大小写
$2~/th/
:第2
列包含th
9、处理2个文件的情况。需要以a
文件的第3
列在b
文件中进行过滤
awk -F "|" 'NR==FNR{a[$1]=$2}{if($1 ~ /^11\.[0-9]*\.[3,5]\.[0-9]*/) print $0,a[$3]}' b.txt a.txt
NR==FNR{a[$1]=$2}
a
是一个数组;当NR==FNR
,也就是读取第一个文件的内容(第一个文件就是后面的b.txt
),以b.txt
中的$1
作为数组索引号,以b.txt
中的$2
作为数组的值;
if($1 ~ /^11\.[0-9]*\.[3,5]\.[0-9]*/) print $0,a[$3]
以a.txt
的第一列做正则匹配,同时输出$0
,也就是所有列的内容。a[$3]
,数组是不变的,这里以a.txt
文件的第3
列为key
,输出value
(如果key不存在时,则不做处理。这顺其自然就相当于过滤了b.txt的内容)
awk gsub
awk
内置函数gsub
gsub()
:gsub(r,s)
在整个$0
中用s
替代r
;gsub(r,s,t)
在整个t
中用s
替代r
此函数的另外的一个功能就是统计某个字符在一行中出现的次数
➜ test cat a
sdhi bb
12 jj
bn 213hi
kjdhi bb hi hi
sjd 213hi
➜ test cat a | awk '{print NR,gsub("hi", "xx"),$0}'
1 1 sdxx bb
2 0 12 jj
3 1 bn 213xx
4 3 kjdxx bb xx xx
5 1 sjd 213xx
第一列:行号
第二列:hi
字符被替换的次数
第三列:输出替换后的整行内容
awk总结
awk
被誉为Linux
下的文本处理三剑客之一,也是三剑客的第一个,它具有很强的文本处理能力,有些时候不一定要写很复杂的程序才能完成日志分析,其实用很简单的Linux
命令就能完成需求,而且效率非常高。awk
就是其中之一,剩下2
个是sed
和grep
,下一篇文章我们再来分享sed
命令!