awk命令来自三位创始人Alfred Aho、Peter Weinberger、Brian Kernighan的姓氏缩写,其功能是对文本和数据进行处理。使用awk命令可以让用户自定义函数或正则表达式,对文本内容进行高效管理,awk与sed、grep并称为Linux系统中的“文本三剑客”。
AWK和sed的区别
- AWK更像是脚本语言;
- AWK用于"比较规范"的文本处理,用于统计数量并输出指定:字段;
- 使用sed将不规范的文本,处理为"比较规范"的文本。
语法格式: awk 参数 文件名
AWK脚本的流程控制
- 输入数据前例程:BEGIN{ }
- 主输入循环:{ }
- 所有文件读取完成例程:END{ }
AWK字段
AWK的字段引用和分离
- 记录和字段
- 每行称作AWK的记录
- 使用空格、制表符分隔开的单词称作字段
- 可以自行设定分隔的字段
- 字段的引用
- awk中使用$1、$2 、... 、$n表示第几个字段,例如:
awk '{print $1,$2,$3}' filename
- awk可以使用-F选项改变字段分隔符,例如:
awk -F ":" '{print $1,$2,$3}' filename
- 分隔符可以使用正则表达式,例如:
cat /boot/grubs/grub.cfg
备注:grub.cfg 文件包含了 GRUB 用来引导操作系统所需的所有配置和菜单项,其中包含内核版本信息,如下:
我们现在需要做的就是提取出图中标注的信息:
- 打印grub.cfg文件中,以menu开头的整行内容
awk '/^menu/{print $0}' /boot/grub2/grub.cfg
- 打印grub.cfg文件中,以menu开头的行中的内核信息
awk -F "'" '/^menu/{print $2}' /boot/grub2/grub.cfg
- 打印grub.cfg文件中,以menu开头的行中的第2个字段,并在每行前添加行号
awk -F "'" '/^menu/{print x++,$2}' /boot/grub2/grub.cfg
AWK的表达式
赋值操作符
- = 是最常用的赋值操作符
- var1="name"
- var2="hello" "world
- var3=$1
- 其他赋值操作符
- ++ -- += -= *= /= %= ^=
- ++表示加1,--表示减1
算术操作符
- + - * / % ^
系统变量
字段分隔符FS和OFS
- FS(Field Separator )表示输入的字段分隔符,对于输入的文件已什么样的符号作为字符分隔符判断
- OFS(Output Field Separator)表示输出的字段分隔符
- 分隔符默认是空格或制表符
举例:
head -5 /etc/passw
- 显示文件passwd的前5行内容,然后以“:”作为分隔符,筛选出其中每一行的第1个字段(即第1列)显示。
head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $1}'
如图所示:
- 显示文件passwd的前5行内容,然后以“:”作为分隔符,筛选出其中每一行的第1个字段(即第1列)和第2个字段(即第2列)显示。
head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $1,$2}'
备注:未指定分隔符的情况下,分隔符默认为空格或制表符
- 显示文件passwd的前5行内容,然后以“:”作为输入分隔符(FS),筛选出其中每一行的第1个字段(即第1列)和第2个字段(即第2列),再然后两个字段之间以“-”为输出分隔符(即OFS)显示。
head -5 /etc/passwd | awk 'BEGIN{FS=":";OFS="-"}{print $1,$2}'
记录分隔符RS
- RS(Record Separator)用于标记输入的行的分隔符(默认是换行符[\n]),一般在多行合并为单行处理时用到
举例:
- 显示文件passwd的前5行内容,然后以冒号(:)为记录分隔符显示整行信息。
head -5 /etc/passwd | awk 'BEGIN{RS=":"}{print $0}'
备注:以冒号(:)为记录分隔符,具体如何来理解?
表示在读到内容遇到冒号(:)时,会认为该行已结束,后面的内容是新的一行,如上图命令执行结果所示。
NR和FNR行数
- NR(Number of Record)
- FNR(File Number of Record )
两者均用于显示行号,区别在于同时显示多个文件,NR在显示行号时,会累加,不会重排,而FNR会根据每个文件,行号会重排。
举例:
- 显示文件passwd的前5行内容,然后显示这5行的行号(仅显示行号,不显示内容)。
head -5 /etc/passwd | awk '{print NR}'
- 显示文件passwd的前5行内容,然后显示这5行的行号,同时显示每一行的整行内容,如下:
head -5 /etc/passwd | awk '{print NR,$0}'
- 显示文件passwd的前5行内容,然后显示这5行的行号,同时显示每一行的整行内容,如下:
head -5 /etc/passwd | awk '{print FNR,$0}'
从第2/3例,可以看到,在显示单个文件时,NR和FNR功能完全相同
- 在显示多个文件时,如下
awk '{print NR,$0}' /etc/hosts /etc/hosts
awk '{print FNR,$0}' /etc/hosts /etc/hosts
- 以“:”作为输入分隔符(FS),输出显示文件passwd内容中的第2行的第7个字段
awk -F ":" 'NR==2 {print $7}' /etc/passwd
- 以“:”作为输入分隔符(FS),输出显示文件passwd内容中的第1行的第7个字段和第2行的第7个字段
awk -F ":" 'NR==1{print $7} NR==2{print $7}' /etc/passwd
NF字段数量
- NF(Number of Field)最后一个字段内容可以用$NF取出
举例:
- 显示文件passwd的前5行内容,然后将这些内容作为awk命令的输入,以冒号(:)作为字段分隔符,输出每一行的字段数
head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print NF}'
- 显示文件passwd的前5行内容,然后将这些内容作为awk命令的输入,以冒号(:)作为字段分隔符,输出每一行第$NF行(即$7)字段
head -5 /etc/passwd | awk 'BEGIN{FS=":"}{print $NF}'
综合应用示例
cat -n password
cat password | awk 'BEGIN{FS=":";RS="-"} NR==1{print $2}'
命令解析:
cat命令查看文本文件passwd内容,然后通过awk命令筛选内容,
内容筛选分为两个步骤,
- 第一个步骤:划分文本passwd的内容
通过命令的第一部分BEGIN{FS=":";RS="-"}来对内容进行划分,这一步骤执行后的结果为:
- 第二个步骤:筛选输出内容
通过命令中的NR1{print $2},首先通过NR1筛选出上图中的第一行内容root:x,然后通过$2,筛选出这一行的第2个字段x。
关系操作符
布尔操作符
AWK的条件语句和循环语句
条件语句
条件语句使用if开头,根据表达式的结果来判断执行哪一条语句
如下:
if (表达式)
awk语句1
[else
awk语句2
]
注:
- 语句中表达式成功时,返回值为1;不成立时,返回值为0;
- 如果有多个语句要执行,可以将awk语句的部分用{ }括起来,看例2;
举例:
样例文件kpi.txt,内容是5个员工名称及对应每个人半年内的kpi打分
cat kpi.txt
- 要求 输出第2个月份的kpi分值 大于等于80分的 员工名称
awk '{if($2>=80) print $1}' kpi.txt
#大括号{}中所有项之间可以完全不加空格
- 要求 输出 第2个月份的kpi分值大于等于80分的 员工名称和kpi分值
awk '{if($2>=80) {print $1;print $2} }' kpi.txt
注:
多条awk语句,如果不加大括号{ },会如何显示,如下:
awk '{if($2>=80) print $1;print $2}' kpi.txt
这里就不详细讲了,自行测试下吧
循环语句
第一种:while循环
while(表达式)
awk语句1
第二种:do循环
do{
awk语句1
}while(表达式)
第三种:for循环
for(初始值;循环判断条件;累加)
awk语句1
影响控制的其他语句
- break
- continue
举例:
- 33333333333
- 4444444444
没写完,会一点点优化更新