一. gawk 基础
gawk 程序脚本用一对花括号来定义,必须将命令放到两个花括号中。由于 gawk 命令行假定脚本是单个文本字符串,所以还必须将脚本放到单引号中。
gawk 允许将多条命令组合成一个正常的程序。要在命令行上的程序脚本中使用多条命令,只要在命令之间加分号即可。
gawk 具有如下功能:
-
定义变量来保存数据
-
使用算术和字符串操作符来处理数据
-
使用结构化编程概念来为数据处理增加处理逻辑
-
通过提取数据文件中的数据元素,将其重新排列或格式化,生成格式化报告
(一). 命令格式
gawk options program file
选项 | 描述 |
---|---|
-F fs | 指定行中划分数据字段的字段分隔符 |
-f file | 从指定的文件中读取程序 |
-v var=value | 定义gawk程序中的一个变量及其默认值 |
-mf N | 指定要处理的数据文件中的最大字段数 |
-mr N | 指定数据文件中的最大数据行数 |
-W keyword | 指定 gawk 的兼容模式或警告等级 |
(二). BEGIN 关键字
gawk 允许指定程序脚本何时运行。gawk 默认会从输入中读取一行文本,然后针对该行的数据执行程序脚本。有时可能需要在处理数据前运行脚本,比如为报告创建标题。BEGIN 关键字会强制 gawk 在读取数据前执行 BEGIN 关键字后指定的程序脚本。
$ cat data.txt
Line 1
Line 2
Line 3
$ gawk 'BEGIN {print "The data3 File Contents:"} {print $0}' data.txt
The data3 File Contents:
Line 1
Line 2
Line 3
(三). END 关键字
与 BEGIN 关键字类似,END 关键字允许指定一个程序脚本,gawk 会在读完数据后执行它。
$ gawk '{print $0} END {print "End of file"}' data.txt
Line 1
Line 2
Line 3
End of file
二. 使用变量
gawk 支持两种不同类型的变量:内建变量、自定义变量。内建变量存放用来处理数据文件中的数据字段和记录的信息。
(一). 内建变量
1. 字段变量
字段变量允许使用美元符号 $ 和字段在该记录中的位置来引用记录对应的字段。因此使用 $0 代表整行文本,使用 $1 引用记录中的第一个数据字段,使用 $2 引用第二个字段,依次类推。
2. 分隔符变量
字段变量是由字段分隔符来划定的。
变量 | 描述 |
---|---|
FIELDWIDTHS | 由空格分隔的一列数字,定义了每个数据字段确切宽度 |
FS | 输入字段分隔符 (默认为空白字符) |
RS | 输入记录分隔符 (默认为换行符) |
OFS | 输出字段分隔符 (默认为空格) |
ORS | 输出记录分隔符 (默认为换行符) |
FIELDWIDTHS 变量允许我们不依靠字段分隔符来读取记录。在一些应用中,数据并没有使用字段分隔符,而是被放置在了记录中的特定列。这种情况下,必须设定 FIELDWIDTHS 变量来匹配数据在记录中的位置。
一旦设置了 FIELDWIDTH 变量, gawk 就会忽略 FS 变量,并根据提供的字段宽度来计算字段。一旦设定了 FIELDWIDTHS 变量的值,就不能再改变了。
$ cat data.txt
1005.3247596.37
115-2.349194.00
05810.1298100.1
$ gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"} {print $1,$2,$3,$4}' data.txt
100 5.324 75 96.37
115 -2.34 91 94.00
058 10.12 98 100.1
3. 数据变量
变量 | 描述 |
---|---|
ARGC | 当前命令行参数个数 |
ARGIND | 当前文件在 ARGV 中的位置 |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字的转换格式,默认值为%.6 g |
ENVIRON | 当前 shell 环境变量及其值组成的关联数组 |
ERRNO | 当读取或关闭输入文件发生错误时的系统错误号 |
FILENAME | 用作 gawk 输入数据的数据文件的文件名 |
FNR | 当前数据文件中的数据行数 |
IGNORECASE | 设成非零值时,忽略 gawk 命令中出现的字符串的字符大小写 |
NF | 数据文件中的字段总数 |
NR | 已处理的输入记录数 |
OFMT | 数字的输出格式,默认值为 %.6 g |
RLENGTH | 由 match 函数所匹配的子字符串的长度 |
RSTART | 由 match 函数所匹配的子字符串的起始位置 |
ARGC 和 ARGV 变量允许从 shell 中获得命令行参数的总数以及它们的值。但这可能有点麻烦,因为 gawk 并不会将程序脚本当成命令行参数的一部分。
$ gawk 'BEGIN {print ARGC,ARGV[0],ARGV[1]}' data.txt
2 gawk data.txt
ENVIRON 变量使用关联数组来提取 shell 环境变量。数组索引中的文本是环境变量名,而数组的值则是对应环境变量的值。
$ gawk 'BEGIN {print ENVIRON["HOME"]; print ENVIRON["PATH"]}'
/root
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
如果只使用一个数据文件作为输入,FNR 和 NR 的值是相同的;如果使用多个数据文件作为输入,FNR 的值会在处理每个数据文件时被重置,而 NR 的值则会继续计数直到处理完所有的数据文件。
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ gawk 'BEGIN{FS=","}{print $1,"NFR="FNR,"NR="NR}' data.txt data.txt
data11 NFR=1 NR=1
data21 NFR=2 NR=2
data31 NFR=3 NR=3
data11 NFR=1 NR=4
data21 NFR=2 NR=5
data31 NFR=3 NR=6
(二). 自定义变量
gawk 自定义变量名可以是任意数目的字母、数字和下划线,但不能以数字开头。变量名区分大小写。
1. 在脚本中给变量赋值
$ gawk 'BEGIN {test="this is a test"; print test}'
this is a test
$ gawk 'BEGIN {x=4; x=x*2+3; print x}'
11
2. 在命令行给变量赋值
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ cat script
BEGIN {FS=","}
{print $n}
$ gawk -f script n=2 data.txt
data12
data22
data32
使用命令行参数来定义变量的值会有一个问题,这个值在代码的 BEGIN 部分不可用。可以用 -v 命令行参数来解决这个问题。它允许在 BEGIN 代码之前设定变量。在命令行上,-v 命令行参数必须放在脚本代码之前。
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ cat script
BEGIN {FS=",";print "The value is", n}
{print $n}
$ gawk -f script n=2 data.txt
The value is
data12
data22
data32
$ gawk -v n=2 -f script data.txt
The value is 2
data12
data22
data32
三. 处理数组
在 gawk 中使用关联数组提供数组的功能。关联数组不需要使用连续的数字来标识数组中的数据元素,而是用各种字符串来引用值。每个索引字符串都必须能够唯一地标识出赋给它的数据元素。
(一). 定义数组
数组变量赋值的格式为:var[index] = element。其中 var 是变量名,index 是关联数组的索引值,element 是数据元素值。
$ gawk 'BEGIN {
num[1]=2
num[2]=3
str["name"]="ziqing"
total=num[1]+num[2]
print str["name"],total
}'
ziqing 5
(二). 遍历数组
如果要在 gawk 中遍历一个关联数组,可以用特殊的 for 语句。for 语句在每次循环时将关联数组 array 的下一个索引值赋给变量 var,然后执行一遍 statements。这个变量中存储的是索引值而不是数组元素值。索引值不会按任何特定顺序返回。
for (var in array)
{
statements
}
$ gawk 'BEGIN {
arr["a"]=1
arr["b"]=2
arr["c"]=3
arr["d"]=4
for (var in arr)
{
print "key:",var," value:",arr[var]
}
}'
key: a value: 1
key: b value: 2
key: c value: 3
key: d value: 4
(三). 删除数组变量
从关联数组中删除数组索引要用一个特殊的命令:delete array[index]。删除命令会从数组中删除关联索引值和相关的数据元素值。
$ gawk 'BEGIN {
arr["a"]=1
arr["b"]=2
arr["c"]=3
arr["d"]=4
for (var in arr)
{
print "key:",var," value:",arr[var]
}
print "============="
delete arr["b"]
for (var in arr)
{
print "key:",var," value:",arr[var]
}
}'
key: a value: 1
key: b value: 2
key: c value: 3
key: d value: 4
=============
key: a value: 1
key: c value: 3
key: d value: 4
四. 使用模式
(一). 正则表达式
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ gawk 'BEGIN{FS=","} /11/{print $1,$2}' data.txt
data11 data12
(二). 匹配操作符
匹配操作符 (~) 允许将正则表达式限定在记录中的特定数据字段。可以指定匹配操作符、数据字段变量以及要匹配的正则表达式。也可以用 ! 符号来排除正则表达式的匹配。
$ cat data.txt
data11,data12,data13,data14,data15
data21,data22,data23,data24,data25
data31,data32,data33,data34,data35
$ gawk 'BEGIN{FS=","} $1 ~ /^data2/{print $1,$2}' data.txt
data21 data22
$ gawk 'BEGIN{FS=","} $1 !~ /^data2/{print $1,$2}' data.txt
data11 data12
data31 data32
(三). 数学表达式
可以在匹配模式中使用数学表达式。这在匹配数据字段中的数字值时非常方便。也可以对文本数据使用表达式,数据必须跟模式严格匹配。
$ gawk -F: '$4 == 0{print $1}' /etc/passwd
root
sync
shutdown
halt
operator
五. 结构化命令
(一). if 语句
if (condition) statement1
if (condition) statement1; else statement2
$ cat data.txt
10
5
13
50
34
$ gawk '{if($1 > 20) print $1}' data.txt
50
34
$ cat data.txt
10
5
13
50
34
$ gawk '{if($1 > 20) print $1; else print $1 *2}' data.txt
20
10
26
50
34
(二). while 语句
gawk 支持在 while 循环中使用 break 语句和 continue 语句,允许从循环中跳出。
while (condition)
{
statements
}
$ cat data.txt
130 120 135
160 113 140
145 170 215
$ gawk '{i=1;total=0;while(i<4){total=total+$i;i++;};print "total: "total}' data.txt
total: 385
total: 413
total: 530
(三). do-while 语句
do
{
statements
} while (condition)
$ cat data.txt
130 120 135
160 113 140
145 170 215
$ gawk '{
i=1;total=0
do{total=total+$i;i++;}while(total<150)
print "total:"total
}' data.txt
total:250
total:160
total:315
(四). for 语句
for( variable assignment; condition; iteration process)
$ gawk 'BEGIN{total=0;for(i=1;i<=10;i++)(total=total+i);print "total: "total}'
total: 55
六. 格式化打印
gawk 中的 printf 命令允许指定具体如何显示数据的指令。
printf "format string", var1, var2 . . .
format string 是格式化输出的关键。它会用文本元素和格式化指定符来具体指定如何呈现格式化输出。格式化指定符会指明显示什么类型的变量以及如何显示。gawk 会将每个格式化指定符作为占位符,供命令中的变量使用。第一个格式化指定符对应列出的第一个变量,第二个对应第二个变量,依此类推。
格式化指定符格式:%[modifier]control-letter。其中 control-letter 是一个单字符代码,用于指明显示什么类型的数据,而 modifier 则定义了可选的格式化特性。
控制字母 | 描述 |
---|---|
c | 将一个数作为 ASCII 字符显示 |
d | 显示一个整数值 |
i | 显示一个整数值(跟 d 一样) |
e | 用科学计数法显示一个数 |
f | 显示一个浮点值 |
g | 用科学计数法或浮点数显示(选择较短的格式) |
o | 显示一个八进制值 |
s | 显示一个文本字符串 |
x | 显示一个十六进制值 |
X | 显示一个十六进制值,但用大写字母 A~F |
除了控制字母外,还有 3 种修饰符可以用来进一步控制输出:
-
width,指定输出字段最小宽度的数字值。如果输出短于这个值,printf 会将文本右对齐,并用空格进行填充。如果输出比指定的宽度还要长,则按照实际的长度输出
-
prec,指定浮点数中小数点后面位数,或者文本字符串中显示的最大字符数
-
-,指明在向格式化空间中放入数据时采用左对齐而不是右对齐
七. 内建函数
一. 数学函数
函数 | 描述 |
---|---|
atan2(x, y) | x/y 的反正切, x 和y 以弧度为单位 |
cos(x) | x 的余弦, x 以弧度为单位 |
exp(x) | x 的指数函数 |
int(x) | x 的整数部分,取靠近零一侧的值 |
log(x) | x 的自然对数 |
rand( ) | 比 0 大比 1 小的随机浮点值 |
sin(x) | x 的正弦, x 以弧度为单位 |
sqrt(x) | x 的平方根 |
srand(x) | 为计算随机数指定一个种子值 |
int() 会生成一个值的整数部分,但并不会四舍五入取近似值。它会生成该值和 0 之间最接近该值的整数。
函数 | 描述 |
---|---|
and(v1, v2) | 执行值 v1 和 v2 的按位与运算 |
compl(val) | 执行 val 的补运算 |
lshift(val, count) | 将值 val 左移 count 位 |
or(v1, v2) | 执行值 v1 和 v2 的按位或运算 |
rshift(val, count) | 将值val右移 count 位 |
xor(v1, v2) | 执行值 v1 和 v2 的按位异或运算 |
二. 字符串函数
asort(s [,d])
将数组 s 按数据元素值排序。索引值会被替换成表示新的排序顺序的连续数字。如果指定了d,则排序后的数组会存储在数组 d 中。
asorti(s [,d])
将数组 s 按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字索引来表明排序顺序。另外如果指定了 d,排序后的数组会存储在数组 d 中。
gensub(r, s, h [, t])
查找变量 $0 或目标字符串 t 来匹配正则表达式 r。如果 h 是一个以 g 或 G 开头的字符串,就用 s 替换掉匹配的文本。如果 h 是一个数字,它表示要替换掉第 h 处 r 匹配的地方。
gsub(r, s [,t])
查找变量 $0 或目标字符串 t来匹配正则表达式 r。如果找到了,就全部替换成字符串 s。
index(s, t)
返回字符串t在字符串 s 中的索引值,如果没找到的话返回 0
length([s])
返回字符串 s 的长度;如果没有指定的话,返回 $0 的长度。
match(s, r [,a])
返回字符串 s 中正则表达式 r 出现位置的索引。如果指定了数组 a,它会存储 s 中匹配正则表达式的那部分。
split(s, a [,r])
将 s 用 FS 字符或正则表达式 r 分开放到数组 a 中。返回字段的总数。
sprintf(format,variables)
用提供的 format 和 variables 返回一个类似于 printf 输出的字符串。
sub(r, s [,t])
在变量 $0 或目标字符串t中查找正则表达式r的匹配。如果找到了,就用字符串 s 替换掉第一处匹配。
substr(s, i [,n])
返回 s 中从索引值 i 开始的 n 个字符组成的子字符串。如果未提供 n,则返回 s 剩下的部分。
tolower(s)
将 s 中的所有字符转换成小写。
toupper(s)
将 s 中的所有字符转换成大写。
三. 时间函数
函数 | 描述 |
---|---|
mktime(datespec) | 将一个按 YYYY MM DD HH MM SS [DST] 格式指定的日期转换成时间戳值 |
strftime(format[,timestamp]) | 将当前时间的时间戳或 timestamp 转化格式化日期 |
systime( ) | 返回当前时间的时间戳 |
网友评论