【Linux】gawk详解
什么是 gawk
gawk是Unix中原始awk程序的GNU版本,可以将gawk看成是一种编程语言,并用它处理数据。
gawk的执行流程和sed类似,首先从标准输入stdin或者文件中读取数据,每次读取一行,并针对该行数据执行脚本命令,然后继续读取下一行并重复前面的操作。
gawk 命令格式
gawk命令格式为:
|
|
1. options
常见的options为:
-
-F fs指定每行数据的字段分隔符,如
-F;表示以;为字段分隔符。默认的字段分隔符是空白字符(空格或者制表符)。
-
-f filegawk程序可以预先写在文件中,-f用于从指定文件读取程序。 -
-v var=value为
gawk程序定义变量。
2. program
gawk的脚本命令必须放在花括号{}中,如:
|
|
程序命令可以有多条,如果多条命令位于同一行,需要用;分开。如:
|
|
多条命令也可以位于多行,此时,多条命令之间不需要分隔符。如:
|
|
在对数据进行处理前,可以执行指定命令,这些命令放在BEGIN命令块中。如:
|
|
数据处理结束后,也可以执行指定命令,这些命令放在END命令块中。如:
|
|
如果只指定了BEGIN命令块或者END命令块,缺少数据处理命令,则不会对输入数据做任何操作。
3. file
如果gawk命令行中没有指定file,则从标准输入读取数据,否则就从指定文件读取数据。
如:执行命令gawk '{print "hello world"}'后,程序会从stdin接收数据,并打印hello world。此时,可以使用Ctrl + d组合键来终止程序,该组合键会发送EOF字符。
变量
1. 数据字段变量
每行的数据字段都会对应一个变量,字段是根据字段分隔符来划分的。
-
$0:代表整行文本。 -
$1:代表第一个字段。 -
$2:代表第二个字段。 -
$n:代表第n个字段。
2. 内建变量
假设data.txt是一个文本文件。
-
FIELDWIDTHS
该命令后面会跟上一串数字,如
"3 2 1",用来定义每个数据字段的宽度。如:1gawk 'BEGIN{FIELDWIDTHS="3 2 1"} {print $1, $2, $3}' data.txt使用了
FIELDWIDTHS后,字段分隔符会被忽略。 -
FS
指定输入数据的字段分隔符。如:
1gawk 'BEGIN{FS=":"} {print $1, $2, $3}' data.txt -
RS
指定输入数据的行分隔符。如:
1 2# 指定空白行为行分隔符 gawk 'BEGIN{RS=""} {print $0}' data.txt -
OFS
指定输出数据的字段分隔符。如:
1gawk 'BEGIN{OFS=";"} {print $1, $2, $3}' data.txt -
ORS
指定输出数据的行分隔符。如:
1gawk 'BEGIN{ORS=","} {print $0}' data.txt -
ARGC
存放的是当前命令行参数的个数。如:
1gawk '{print ARGC}' data.txt data.txt # 输出是3,脚本命令和选项不参与计数 -
ARGV
由命令行参数组成的数组。如:
1 2 3gawk '{print ARGC, ARGV[0], ARGV[1]}' data.txt # 2 gawk data.txt -
ARGIND
表示当前文件在
ARGV中的位置。如:1gawk '{print ARGIND}' data.txt data.txt # 1 2 -
ENVIRON
由当前
shell环境变量组成的关联数组。如:1 2# 输出HOME目录 gawk '{print ENVIRON["HOME"]}' data.txt -
FILENAME
当前文件的文件名。如:
1gawk '{print FILENAME}' data.txt # data.txt -
NF
当前行的字段总数。如:
1gawk '{print NF, $NF}' data.txt -
FNR
当前文件已读取的数据行数,遇到新的文件时,会重新从1开始计数。如:
1gawk '{print FNR}' data.txt data.txt # 1 1 -
NR
已读取的总数据行数,遇到新文件时,会进行累计,而不是重新计数。如:
1gawk '{print NR}' data.txt data.txt # 1 2
3. 自定义变量
变量名由字母、数字、下划线组成,但是不能以数字开头。
自定义变量的定义方式由多种:
-
在程序脚本中定义变量。如:
1 2 3gawk 'BEGIN{test="test line"; print test; test=1; print test}' # test line # 1 -
在命令行中定义变量,且变量定义位于程序脚本之后。如:
1gawk '{print $n}' n=1 data.txt这种方式定义的变量,不能在
BEGIN命令块中使用。 -
在命令行中定义变量,且变量定义位于程序脚本之前。此时需要使用
-v选项。如:1gawk -v n=2 'BEGIN{print n}'
数组
gawk编程语言使用关联数组来实现数组功能。
关联数组的索引值不再必须是连续的数字,而是可以使用任意文本字符串。
1. 数组定义
定义方式为:
|
|
索引查找方式为:
|
|
2. 遍历数组
数组遍历的语法为:
|
|
如果statements只有一行,则可以省略外层的花括号,如:
|
|
数组遍历的结果是没有固定顺序的。
3. 删除数组中的变量
删除语法为:
|
|
算数运算符
gawk支持下列算数运算符:
-
+:加。 -
-:减。 -
*:乘。 -
/:除。 -
%:取余。 -
^或者**:乘方。 -
++x:x加1,然后返回x。 -
x++:先返回x,然后x加一。 -
--x:x减一,然后返回x。 -
x--:先返回x,然后x减一。
模式
在gawk程序脚本中,可以使用不同类型的匹配模式,来过滤数据行。
BEGIN和END可以看成是两个特殊模式。
1. 正则表达式
可以使用正则表达式,来对数据行进行匹配。如:
|
|
该命令会匹配包含root的数据行。
还可以使用匹配操作符~,来对某个特定字段进行匹配,如:
|
|
该命令会匹配第一个字段以root开头的数据行。
还可以使用!~来排除匹配行。如:
|
|
该命令会过滤第一个字段以root开头的数据行。
2. 数学比较表达式
可以使用的数学比较表达式有:
-
x == y
-
x <= y
-
x < y
-
x >= y
-
x > y
比较双方,既可以为数字,也可以是任意字符串。
流程控制语句
gawk支持多种流程控制语句:
-
if...else...、 -
while...、 -
do...while...、 -
for循环
1. if…else…
语法格式为:
|
|
如果statement只有一行命令,则可以省略外层花括号。
还可以将上述命令写成一行。此时,在省略花括号的情况下,必须用分号分隔每个if语句。
2. while…
语法格式为:
|
|
可以使用break或者continue跳出循环。
3. do…while…
语法格式为:
|
|
4. for循环
gawk支持c语言风格的for循环。语法格式为:
|
|
printf
gawk可以使用printf进行格式化打印。
printf的命令格式为:
|
|
format string是格式化字符,其中包含文本字符和占位符。
占位符格式为:%[modifier]control-letter,modifier是修饰符,control-letter是控制字符。
control-letter列表如下:
-
c:以
ASCII形式显示。如:1 2gawk 'BEGIN{printf "%c\n", 65}' # A -
d:显示整数值。如:
1 2gawk 'BEGIN{printf "%d\n", 65}' # 65 -
i:显示整数值,和
d一样。如:1gawk 'BEGIN{printf "%i\n", 65}' -
e:以科学记数法形式显示一个数。如:
1 2gawk 'BEGIN{printf "%.2e\n", 100000}' # 1.00e+05 -
f:显示浮点数。如:
1 2gawk 'BEGIN{printf "%f\n", 3.141}' # 3.141000 -
g:用科学记数法或浮点数显示(选择较短的格式)。如:
1 2gawk 'BEGIN{printf "%g\n", 0.0000001}' # 1e-07 -
o:显示为八进制。如:
1 2gawk 'BEGIN{printf "%o\n", 10}' # 12 -
s:打印一个字符串。
1 2gawk 'BEGIN{printf "%s\n", "hello world"}' # hello world -
x:显示为十六进制。如:
1 2gawk 'BEGIN{printf "%x\n", 10}' # a -
X:显示为十六进制,但是使用大写A~F。
1 2gawk 'BEGIN{printf "%X\n", 10}' # A
modifier如下:
-
width:输出字段最小宽度。 -
prec:指定浮点数的最小宽度和精度。 -
-:文本设置为左对齐,默认是右对齐。 -
+:文本设置为右对齐。 -
#:在八进制数前显示0,在十六进制前显示0x。
结语
gawk还有很多有用的特性,如函数等,对此暂时不做说明。