Awk简介

Awk是一种编程语言,诞生于1977年,其名称为三位作者姓的首字母缩写:
Alfred Aho 、Peter Weinberger 和 Brian Kernighan
awk主要用于linux/unix下对文本和数据进行扫描处理
数据可以来自标准输入,文件,管道

awk有众多的发行版本,awk,nawk,gawk,MKS awk,tawk包括开源产品和商业产品
目前linux中常用的swk编译器版本mawk,gawk
rhel系统默认的为gawk
ubuntu系列产品用mawk

此文章用gawk实现,GUN开源项目awk解释器的开源代码实现

Awk工作流程

首先对文件逐行扫描,从第一行到最后一行,逐行进行匹配特定模式的行,并在这些行上进行用户想要的操作,
Awk基本结构由模式匹配和处理过程(处理动作)组成
pattern  {action}

注意:awk读取文件每一行时,将对该行与给定的模式相匹配,如果匹配,则处理执行处理过程,否则不做任何操作,
如果没有指定处理脚本,则把匹配的行标准输出,默认处理动作为print打印
如果没有指定模式匹配,则默认匹配所有数据

Awk有俩个特殊模式,BEGIN/END,被放置在没有读取任何数据之前以及在所有数据读取完成后执行

Awk的基础语法

格式:
gawk  [选项] -f program-file  [--] file 

#选项:
-F fs, --field-separator fs
指定fs为输入行的分隔符(默认的分隔符为空格或制表符)

-v var=val,--assign var=val
在执行处理动作之前,设置一个变量var值为var

-f program-file,--file program-file
从脚本文件中读取awk指令,以取代在命令参数中输入脚本

-W compat,-W traditional,--compat,--traditional
使用兼容模式运行AWK,GUN拓展选项将被忽略

-W dump-variables[=file] ,--dump-variables[=file]
打印全局变量(变量名,类型,值)到文件中,
如果没有提供文件名,则自动输出至名为dump-variables文件中(演示失败)

-W copyleft ,-W copyright,--copyleft,--copyright
输出打印简短的GUN版本信息
  • awk程序语法结构:一个awk程序包含一系列的模式{动作指令}或者函数定义
  • 模式可以是BEGIN/END/表达式用来限定操作对象的多个表达式使用逗号隔开
  • 动作指令需要用{}引起来

案例

1。使用正则表达式匹配空行: /^$/,动作为打印"哈哈哈哈,有空行"
[root@localhost ~]# awk '/^$/ {print "哈哈哈哈,有空行"}' quote.txt 
哈哈哈哈,有空行
哈哈哈哈,有空行
哈哈哈哈,有空行
哈哈哈哈,有空行
[root@localhost ~]# 
2.匹配包含anconda的行,并打印  /etc/syconfig/network
[root@#localhost ~]# awk '/anaconda/' /etc/sysconfig/network
# Created by anaconda
[root@#localhost ~]# 
3.利用脚本文件,判断是否有空行
[root@#localhost ~]# cat awk1.sh 
/^$/  {print "哈哈哈哈哈哈哈啊哈哈啊"}
[root@#localhost ~]# 
[root@#localhost ~]# awk -f awk1.sh quote.txt 
哈哈哈哈哈哈哈啊哈哈啊
哈哈哈哈哈哈哈啊哈哈啊
哈哈哈哈哈哈哈啊哈哈啊
哈哈哈哈哈哈哈啊哈哈啊
[root@#localhost ~]# 

awk操作指令

1.记录与字段
Awk一次从文件中读取一条记录,并将记录存储在字段变量$0中,记录被分割为字段并存储在$1,$2,$3………………$NF中(分隔符默认为空格或制表符)
'NF:内建变量,记录的字段个数'
#输出一段话并输出第一个字段,第二个字段,第三个字段
[root@#localhost ~]# echo I love my gril friend | awk '{print $1,$2,$3}'
I love my
[root@#localhost ~]# echo I love my gril friend | awk '{print $1,$2,$3,$5,$4}'
I love my friend gril
[root@#localhost ~]# 

#读取输入行数并输出该行
[root@#localhost ~]# echo hello world | awk '{print $0,$NF}'
hello world world
[root@#localhost ~]# echo hahahhahaha | awk -F"a" '{print $NF}'

[root@#localhost ~]# echo hahahhahaha | awk -F"h" '{print $NF}'
a
[root@#localhost ~]# 

2.字段与分隔符
默认awk读取数据以空格或制表符作为分隔符
但可以通过-F来改变分隔符

[root@#localhost ~]# awk -F: '{print $1}' /etc/passwd
[root@#localhost ~]# awk 'BEGIN {FS=":"} {print $1}' /etc/passwd

#指定多个分割符
[root@#localhost ~]# echo 'hello the:world,!' | awk 'BEGIN {FS="[:,]"} {print $1,$2,$3,$4}'
hello the world ! 
[root@#localhost ~]#


3.内置变量
变量名称				描述
ARGC			命令行参数个数 -v
FILENAME		当前输入文档的名称
FNR				当前输入文档的记录编号,多个输入文档时有用
'NR				输入流当前记录编号'
'NF				当前记录的字段个数'
FS				字段分隔符
OFS				输出--字段--分隔符,默认是空格
ORS				输出--记录--分隔符,默认换行符 \n
RS				输入记录分隔符,默认换行符

#示例文件
[root@#localhost ~]# cat test1.txt 
This is a test file
Welcome to Jacob's Class
[root@#localhost ~]# cat test2.txt 
Hello the world
Wow! I'm overwhelmed.
Ask for more
[root@#localhost ~]#


#输出当前文档的当前行编号,第一个文件俩行,第二个文件三行
[root@#localhost ~]# awk '{print FNR}' test1.txt test2.txt 


#Awk将俩个文档作为一个整体的输入流,通过NR输入当前编号
[root@#localhost ~]# awk '{print NR}' test1.txt test2.txt


[root@#localhost ~]# awk '{print $1,$2,$3,$4}' test1.txt 
This is a test
Welcome to Jacob's Class'
[root@#localhost ~]# 

#通过OFS将输出分割符设置为'-',print在输出时第1,2,3个字段中间的分割符为‘-’

[root@#localhost ~]# awk 'BEGIN {OFS="-"} {print $1,$2,$3,$4}' test1.txt 
This-is-a-test
Welcome-to-Jacob's-Class
[root@#localhost ~]#

#示例文件
[root@#localhost ~]# cat test3.txt 
mail from:tomcat@gmail.com
subjectLhello
data:2018-11-12 17:00
content:Hello,The world

mail from: jerry@gamil.com
subject:congregation
data:2018-11-12 08:31
content:Congregation to you.

mail from: jacob@gmail.com
subject:Test
data:2018-11-12 10:20
content:This is a test mail
[root@#localhost ~]# 

#读取输入数据,以空白行为记录分割符,即第一个空白行前的内容为一个记录

 [root@#localhost ~]# awk 'BEGIN {FS="\n";RS=""} {print $2}' test3.txt 
subjectLhello
subject:congregation
subject:Test
[root@#localhost ~]# 


 4.表达式与操作
	表达式由变量,常量,函数,正则表达式,操作符组成
	awk中变量有字符和数字变量,如果在awk中定义变量没有初始化,则初始化值为空字符或0
	字符操作一定加引号

	#定义变量
	a='hello'
	b=12
	

	#操作符
	+
	-
	*
	/	除
	%	取余
	^	幂运算
	++
	--
	+=
	-=
	*=
	/=
	>
	<
	>=
	<=
	==  等于
	!=   不等于
	~	匹配
	!~	不匹配
	&&	与
	||	或


	#案例
	
	[root@#localhost ~]# echo test | awk 'x=2 {print x+3}'
	
	[root@#localhost ~]# echo hello | awk 'x=1,y=3 {print x*2,y*3}'
	2 9
	[root@#localhost ~]# 


	#统计所有空白行
	[root@#localhost ~]# awk '/^$/ {print x+=1}' test3.txt 
	1
	2
	[root@#localhost ~]# awk '/^$/ {x+=1} END {print x}' test3.txt 
	2
	[root@#localhost ~]# 

	#打印root用户的UID号
	[root@#localhost ~]# awk -F: '$1~/root/ {print $3}' /etc/passwd
	0
	
	#打印用户uid号大于500的用户
	
	[root@#localhost ~]# awk -F: '$3>500 {print $1}' /etc/passwd
	polkitd
	unbound
	colord
	saslauth
	libstoragemgmt
	nfsnobody
	chrony
	gnome-initial-setup
	hello
	[root@#localhost ~]#