内容预知
1.awk相关知识
AWK是一种优良的文本处理工具。它不仅是 Linux中也是任何环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言:AWK 程序设计语言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
Linux中最常用的文本处理工具有grep,sed,awk。行内将之称为文本三剑客,就功能量和效率来看,awk是当之无愧的文本三剑客之首
逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。
通常awk是将一行数据拆分为多个字段,操作者,可以选取指定的字段对其进行高效率的操作
具体使用方法,在本人前面的博客有记录:
2.awk的基础用法和选项
awk 选项 '模式或条件 {操作}' 文件1 文件2...
awk -f 脚本文件 文件1 文件2
| 内置变量 | 作用 |
| $0 | 当前处理的行的整行内容 |
| $n | 当前处理行的第n个字段(第n列) |
| NR | 当前处理的行的行号(序数) |
| NF | 当前处理的行的字段个数。$NF代表最后一个字段 |
| FS | 列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与"-F"作用相同 |
| OFS | 输出内容的列分隔符 |
| FILENAME | 被处理的文件名 |
| RS | 行分隔符。awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录, 而awk一次仅读入一条记录进行处理。预设值是"\n" |
[root@localhost awk]#awk '{print}' english.txt

另外:0和1放置{ }前,能够起到限制答应的作用(默认为"1")
[root@localhost awk]#awk '{print $0 }' english.txt
[root@localhost awk]#awk '{print NR}' english.txt

[root@localhost awk]#awk '{print NR,$0}' english.txt
- [root@localhost awk]#awk 'NR==3{print}' english.txt
-
- [root@localhost awk]#awk 'NR==3,NR==5{print}' english.txt
-
- [root@localhost awk]#awk '(NR>=3)&&(NR<=5){print}' english.txt
- [root@localhost awk]#awk 'NR%2==0{print}' english.txt
-
- [root@localhost awk]#awk 'NR%2==1{print}' english.txt

getline的工作过程:
(1)当getline左右无重定向符号(“<”)或者管道符号(“|”)时,awk首先读取的是第一行,而getline获取的是是光标跳转至下一行的内容(也就是第二行)。
原因:getline运行之后awk会改变NF,NR,$0,FNR等内部变量,所以此时读取$0的行号不再为1,而是2
拓展:
FNR:awk当前读取的记录数,其变量值小于等于NR,(比如说当读取完第一个文件后,读取第二个文件,FNR是会从0开始进行,而NR不会)。因此读取两个或两个以上的文件,NR==FNR,可以 判断是不是在读取第一个文件
(2)当getline左右有管道符号或重定向符时,getline则作用定向输入文件,由于文件是刚打开,并没有被awk读入一行,而只是getline读入,所以getline返回的是文件的第一行,而不是跳转至一行输入
getline 打印偶数行:
- [root@localhost awk]#awk '{getline;print $0}' english.txt
-
- [root@localhost awk]#seq 10|awk '{getline;print $0}'
getline 打印奇数行 :
- [root@localhost awk]#awk '{print $0;getline}' english.txt
-
- [root@localhost awk]#seq 10|awk '{print $0;getline}'

- [root@localhost awk]#awk '/^root/{print}' /etc/passwd
-
- [root@localhost awk]#awk '/bash$/{print}' /etc/passwd

格式:awk 'BEGIN{...};{...};END{...}' 文件
处理过程:
1、在awk处理指定的文本之前,需要先执行BEGIN{...}模式里的命令操作
2、中间的{...} 是真正用于处理文件的命令操作
3、在awk处理完文件后才会执行END{...}模式里的命令操作。END{ }语句块中,往往会放入打印结果等语句。
引例演示:
[root@localhost awk]#awk 'BEGIN{x=1};{x++};END{print x}' english.txt
拓展提示:
awk是从c语言中继承到Linux,所以在BEGIN模式中变量x,可以直接运用,无需"$"声明获取变量值
普通指定方式:
- [root@localhost awk]#head -n5 /etc/passwd |awk -F':' '{print$3}'
-
- [root@localhost awk]#head -n5 /etc/passwd |awk -F':' '{print$5}'

BEIGIN模式指定:
- [root@localhost awk]#head -n5 /etc/passwd|awk 'BEGIN{FS=":"};{print $5}'
-
- [root@localhost awk]#head -n5 /etc/passwd|awk 'BEGIN{FS=":"};{print $3}'

正向判断打印:
[root@localhost awk]#awk -F: '$3>500{print $0}' /etc/passwd

判断取反打印:
[root@localhost awk]#awk -F: '!($3>10){print $0}' /etc/passwd

除此之外,甚至可以直接进行if语句判断打印:
[root@localhost awk]#awk -F: '{if($3>500){print $0}}' /etc/passwd

3. awk的三元表达式与精准筛选用法
java中: (条件表达式)?(A表达式或者值):(B表达式或者值)
- 条件表达式成立(为真)时,会取冒号前面的值A。 - 条件表达式不成立(为假)时,会取冒号后面的值B。
Shell中: [ 条件表达式 ] && A || B
- 条件表达式成立(为真)时,会取||前面的值A。 - 条件表达式不成立(为假)时,会取||后面的值B。
awk的三元表达式继承了java的用法,格式与Java相似
格式:awk '(条件表达式)?(A表达式或者值):(B表达式或者值)'
[root@localhost awk]# awk -F: '{max=($3>=$4)?$3:$4;{print max,$0}}' /etc/passwd|sed -n '1,6p'
同时:通过管道符sed命令只打印其中的前六行内容

精准筛选方法:
| $n(> < ==) | 用于对比数值 |
| $n~"字符串" | 代表第n个字段 包含 某个字符串的作用 |
| $n!~"字符串" | 代表第n个字段 不包含 某个字符串的作用 |
| $n=="字符串" | 代表第n个字段 为 某个字符串的作用 |
| $n!="字符串" | 代表第n个字段 不为 某个字符串的作用 |
| $NF | 代表最后一个字段 |
运用1:输出第七个字段包含“bash”所在行的第一个字段和最后一个字段
[root@localhost awk]#awk -F: '$7~"bash" {print $1,$NF}' /etc/passwd
运用2:输出第七个字段不包含“nologin”所在行的第一个字段和最后一个字段
[root@localhost awk]#awk -F: '$7!~"nologin" {print $1,$NF}' /etc/passwd

运用3:指定第六个字段为/home/lisi ,第七个字段为/bin/bash,输出满足这些条件所在行的第一个和最后一个字段
[root@localhost awk]#awk -F: '($6=="/home/lisi")&&($7==/bin/bash)"nologin" {print $1,$NF}' /etc/passwd
4.awk的分隔符用法
awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录, 而awk一次仅读入一条记录进行处理。内置变量RS的预设值是"\n"。
但是也可以在使用BEGIN模式在操作前进行行分隔符的改变
[root@localhost awk]#echo $PATH|awk 'BEGIN{RS=":"};{print NR,$0}'

FS 输入时的列分隔符。
OFS 输出内容的列分隔符。($n=$n用于激活,否则不生效,n且必须存在)
对于输出时改变分隔符,我们常用到tr,awk,它们都可以实现在输出内容改变原本的分隔符
- [root@localhost awk]#echo a b c d
-
- [root@localhost awk]#echo a b c d|tr " " ":"

直接修改输出分隔符 :
[root@localhost awk]#echo a b c d|awk '{OFS=":" ; $1=$1;print $0}'

BEGIN模式中修改输出分隔符:
- root@localhost awk]#echo a b c d|awk 'BEGIN{OFS=":"};{$2=$2;print $0}'
-
- [root@localhost awk]#echo a b c d|awk 'BEGIN{OFS=":"};{$3=$3;print $0}'
-
- [root@localhost awk]#echo a b c d|awk 'BEGIN{OFS=":"};{$4=$4;print $0}'
-
- [root@localhost awk]#echo a b c d|awk 'BEGIN{OFS=":"};{$5=$5;print $0}'

5. awk结合数组运用
- [root@localhost awk]#awk 'BEGIN{a[0]=10 ; a[1]=20 ; a[2]=30;print a[1]} '
-
- [root@localhost awk]#awk 'BEGIN{a[0]=10 ; a[1]=20 ; a[2]=30;print a[0]} '
-
- [root@localhost awk]#awk 'BEGIN{a[0]=10 ; a[1]=20 ; a[2]=30;print a[2]} '

此外:awk中的数组还能形成遍历
[root@localhost awk]#awk 'BEGIN{a[0]=10 ; a[1]=20 ; a[2]=30;for(i in a)print i,a[i]} '

- [root@localhost awk]#echo ${arry[@]}|awk -v RS=' ' '!a[$1]++'
-
- [root@localhost awk]#awk -v RS=' ' '!a[$1]++' <<< ${arry[@]}

原理:将文件的字段内容变为定义的数组下标,对其进行匹配读取累加(只有遇到完全一致的才会累加),此时重复的次数在for循环的作用下成为了数组对应下标的元素,
所以输出该下标和元素(就等同于输出重复的字段内容 以及 统计的重复次数)
[root@localhost awk]#awk '{a[$1]++};END{for(i in a){print i,a[i]}}' test.txt

需求:
统计ssh登录失败的用户及其登录失败(日志:/var/log/secure中有记录)的次数(通常我们会认为失败三次,存在着暴力破解登录的可能,意味该主机存在隐患)解决方案:将其筛选出来就把IP加入到黑名单中 /etc/hosts.deny。
纯awk筛选统计:
[root@localhost awk]# awk '/Failed password/{a[$11]++};END{for(i in a){print i,a[i]}}' /var/log/secure

其他awk组合方式:
- [root@localhost awk]#awk '/Failed password/{print $11}' /var/log/secure |sort -n
-
- [root@localhost awk]#awk '/Failed password/{print $11}' /var/log/secure |sort -n |uniq -c

6. 常用awk筛选数据实例
下面有很多的awk获取数据都可以配合脚本加计划性任务编写为一个全自动化运维的检测脚本
[root@localhost awk]#date -d "$(awk -F. '{print $1}' /proc/uptime) second ago" +"%Y%m%d %H:%M:%S"

[root@localhost awk]#ifconfig ens33|awk '/inet /{print $2}'
一般超过百七十,就要注意了!!
[root@localhost awk]#uptime|awk '{print $NF}'

- #入站网卡
- [root@localhost awk]#ifconfig ens33|awk '/RX p/{print $5}'
-
- #出站网卡
- [root@localhost awk]#ifconfig ens33|awk '/TX p/{print $5}'
[root@localhost awk]#free -m |awk '/^Mem/{print $4}'

[root@localhost awk]#df -h|awk '/\/dev\/sda1/{print $4}'

总结
1. awk是一种对文件输出内容的字段(列),进行操作的工具,多数用来提取重要数据
2. awk 结合数组时可以进行数组定义,数组遍历,以及数组元素的去重统计
3.提取文件数据时,注意每行或列的分隔符,正确借用分隔符能够使提取的数据更加精确