一、使用变量
gawk支持两种变量
- 内建变量
- 自定义变量
1.1 内建变量
1.1.1 字段和记录分隔符变量
数据字段变量允许使用美元符号 $ 和 位置来引用对应的字段。 $1 对应第一个数据字段,$2对应第二个数据字段,以此类推。
数据字段用字段分隔符划定。默认情况下,字段分隔符是一个空白字符(空格或制表符)。可以通过 -F选项修改字段分隔符。也可以使用特殊的内建变量FS修改字段分隔符。
有一组内建变量可以控制输入和输出数据中字段和记录的处理方式:
变 量 | 描 述 |
---|---|
FIELDWIDTHS | 由空格分隔的一串数字,定义了每个数据字段的确切宽度 |
FS | 输入字段分隔符 |
RS | 输入记录分隔符 |
OFS | 输出字段分隔符 |
ORS | 输出记录分隔符 |
$ cat < data1
header line
data line 1
End of data line
#默认情况
$ gawk '{print $1,$2}' data1
header line
data line
End of
#1、OFS测试
$ gawk 'BEGIN{OFS="|-|"}
{print $1,$2}' data1
header|-|line
data|-|line
End|-|of
#2、ORS测试
$ gawk 'BEGIN{ORS="|-|"}
{print $1,$2}
END{print "\n"}' data1
header line|-|data line|-|End of|-|
默认输出字段分隔符是空格,第1个例子将输出字段分隔符换成了"|-|“。
默认输出记录分隔符是换行,第2个例子将输出记录分隔符换成了”|-|"。
FIELDWIDTHS会根据提前设置好的字段宽度来划分字段。
下面这个例子将固定格式的时间划分成 年、月、日、时、分。
$ cat <data2
202401011015
202402020900
202403030130
$ gawk 'BEGIN{
FIELDWIDTHS="4 2 2 2 2 2"}
{print $1,$2,$3,$4,$5}' data2
2024 01 01 10 15
2024 02 02 09 00
2024 03 03 01 30
FS默认为空白符,RS默认为换行符。也就是说gawk默认一行为一条记录。但有时一行数据是一个字段,多行数据组成一条记录。这时可以将FS设置成\n,将RS设置成空字符串。
$ cat <data3
zhangsan
17
haerbin
lisi
20
beijing
$ gawk 'BEGIN{FS="\n";RS=""}
{print"name:"$1,"age:"$2,"city:"$3}' data3
name:zhangsan age:17 city:haerbin
name:lisi age:20 city:beijing
1.1.2 数据变量
除了字段和记录分隔符变量外,gawk还提供了其他一些变量帮助了解数据的变化。
变量 | 描述 |
---|---|
ARGC | 命令行参数的数量 |
ARGIND | 当前处理的文件在ARGV中的索引 |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字的转换格式(参见printf语句),默认为%.6g |
ENVIRON | 当前环境变量及其值组成的关联数组 |
ERRNO | 当读取或关闭输入文件发生错误时的系统错误号 |
FILENAME | 用作gawk输入的数据文件的名称 |
FNR | 当前数据文件中已处理的记录数 |
IGNORECASE | 非0表示忽略大小写 |
NF | 数据文件中的字段总数 |
NR | 已处理的输入记录数 |
OFMT | 数字的输出格式。默认值为%.6g。以浮点数或科学计数法表示,以较短者为准,最多是使用6位小数 |
RLENGTH | 由match函数所匹配的子串长度 |
RSTART | 由match函数所匹配的子串的起始位置 |
下面测试几个常用的变量
#ARGC:命令行参数的数量
#ARGV:当前处理的文件在ARGV中的索引
$ gawk 'BEGIN{print ARGC,ARGV[0],ARGV[1],ARGV[2]}' data1 data2
3 gawk data1 data2
#ENVIRON:当前环境变量及其值组成的关联数组
$ gawk 'BEGIN{print ENVIRON["HOME"]}'
/home/ubuntu
#FILENAME :用作gawk输入的数据文件的名称
$ gawk 'END{print FILENAME}' data1
data1
$ cat < data1
header line
data line 1
End of data line
$ cat <data2
202401011015
202402020900
202403030130
#NR:已处理的输入记录数
#FNR:当前数据文件中已处理的记录数
#NF:数据文件中的字段总数
#$NF:最后一个字段的值
$ gawk '{print "NR="NR,"FNR="FNR,"NF="NF,"$NF="$NF}' data1 data2
NR=1 FNR=1 NF=2 $NF=line
NR=2 FNR=2 NF=3 $NF=1
NR=3 FNR=3 NF=4 $NF=line
NR=4 FNR=1 NF=1 $NF=202401011015
NR=5 FNR=2 NF=1 $NF=202402020900
NR=6 FNR=3 NF=1 $NF=202403030130
NR=7 FNR=4 NF=0 $NF=
1.2 自定义变量
gawk的自定义变量由任意个字母、数字和下划线组成,但不能以数字开头。
gawk自定义变量区分大小写。
1.2.1 在脚本中为变量赋值
$ gawk 'BEGIN{test="this is a test.";print test}'
this is a test.
$ gawk 'BEGIN{test=100;print test*(test-1)}'
9900
$ gawk 'BEGIN{test=100;print test^2}'
10000
1.2.2 在命令行中给变量赋值
$ cat <data1
header line
data line 1
End of data line
$ gawk '{print $field}' field=1 data1
header
data
End
$ gawk '{print $field}' field=2 data1
line
line
of
这个例子通过在命令行中给变量赋值,可以显示不同的字段。
这个特性可以在不改变脚本代码的情况下改变脚本的行为。
使用命令行参数定义变量有一个问题:设置变量后,这个变量在BEGIN模块不可用
如下:
$ gawk 'BEGIN {print "field="field}' field=3 data1
field=
可以用 -v选项解决这个问题。-v选项允许在BEGIN之前定义变量。
$ gawk -v field=3 'BEGIN {print "field="field}' field=3 data1
field=3
二、处理数组
数组用于单个变量存储多个值,gawk语言使用关联数组提供数组功能。类似c++中的unorder_map。
2.1 定义数组变量
可以用赋值语句定义数组变量。格式如下;
var[index]=element
var:数组变量名
index:索引
element:索引对应的值
$ gawk 'BEGIN{arr["name"]="lilei";arr["age"]=20;
print arr["name"],arr["age"]}'
lilei 20
2.2 遍历数组变量
格式:
for index in array
{
statement
}
for语句每次循环时会把下一个数组元素的索引赋值给index。
$ gawk 'BEGIN{arr["name"]="lilei";arr["age"]=20;
for (ind in arr)
{
print "arr["ind"]="arr[ind]
}}'
arr[age]=20
arr[name]=lilei
索引没有固定的返回顺序。
2.3 删除数组变量
从关联数组中删除数据需要使用 delete 命令;
delete array[index]
下面使用delete命令的例子
$ cat < gawk_cmd
BEGIN {
arr["name"]="lilei";
arr["age"]=20;
arr["city"]="haerbin";
for (ind in arr)
{
print "arr["ind"] :" arr[ind];
}
delete arr["age"];
print "---------"
for (ind in arr)
{
print "arr["ind"] :" arr[ind];
}
}
$ gawk -f gawk_cmd
arr[age] :20
arr[city] :haerbin
arr[name] :lilei
---------
arr[city] :haerbin
arr[name] :lilei
每行代码后面的分号 ( ; ) 写不写都行。
三、 使用模式
3.1 正则表达式
sed 只支持基础正则表达式(BRE),gawk支持基础正则表达式(BRE) 和扩展正则表达式(ERE)。
下面的第1个例子输出张三的年龄,第2个例子输出年龄在20~30之间的人的名字。
$ cat <data3
zhangsan
17
haerbin
lisi
20
beijing
$ gawk 'BEGIN{FS="\n";RS=""}
/zhangsan/{print $2}' data3
17
$ gawk 'BEGIN{FS="\n";RS=""}
/2./{print $1}' data3
lisi
3.2 匹配操作符
匹配操作符 (~) 使用格式:
数据字段 ~ /正则表达式/
和上面的例子相同,下面第1个例子输出zhangsan的年龄,第2个例子输出年龄在20~30之间的人的名字。
$ gawk 'BEGIN{FS="\n";RS=""}
$1 ~ /zhangsan/{print $1,$2,$3}' data3
zhangsan 17 haerbin
$ gawk 'BEGIN{FS="\n";RS=""}
$2 ~ /^2.$/{print $1,$2,$3}' data3
lisi 20 beijing
3.3 数学表达式
处理正则表达式,gawk还可以在匹配模式中使用数学表达式。
可以使用任何常见的数学表达式:
操作符 | 描述 |
---|---|
== | 等于 |
<= | 小于等于 |
< | 小于 |
> | 大于 |
>= | 大于等于 |
还是相同的例子,输出张三的年龄
$ cat <data3
zhangsan
17
haerbin
lisi
20
beijing
$ gawk 'BEGIN{FS="\n";RS=""}
$1=="zhangsan"{print "age="$2}' data3
age=17
四、结构化命令
gawk 中的结构化命令和 c语言 中的分支和循环结构基本一致。
4.1 if语句
输出年龄是否大于18岁
$ cat <data3
zhangsan
17
haerbin
lisi
20
beijing
$ cat < gawk_cmd
BEGIN {
FS="\n"
RS=""
print "Begin"
}
{
cmp=""
age=18
if ($2 <= age)
{
cmp=" less than "
}
else
{
cmp=" greater than "
}
print $1 cmp,age
}
END{
print "End of file"
}
$ gawk -f gawk_cmd data3
Begin
zhangsan less than 18
lisi greater than 18
End of file
4.2 while 语句
格式:
while (condition)
{
statements
}
下面例子输出某次跳远比赛各个选手的平均成绩。
$ cat < data1
5.5 6.5 7.5
6.6 6.5 6.5
6.6 7.5 5.9
$ cat < gawk_cmd
BEGIN {
print "Begin"
}
{
i=1
sum=0.0
while (i <= NF)
{
sum+=$i
i++
}
print sum/NF
}
END{
print "End of file"
}
$ gawk -f gawk_cmd data1
Begin
6.5
6.53333
6.66667
End of file
4.3 do-while语句
格式:
do
{
statements
}
while (condition)
do-while 与 while 唯一区别是 do-while保证statements会在条件被求值之前至少执行一次。
4.4 for语句
格式:
for (变量赋值; condition; 迭代处理)
{
statements
}
下面使用for语句计算跳远比赛的平均成绩。
$ cat < gawk_cmd
BEGIN {
print "Begin"
}
{
sum=0.0
for(i=1;i<=NF;i++)
{
sum+=$i
}
print sum/NF
}
END{
print "End of file"
}
$ gawk -f gawk_cmd data1
Begin
6.5
6.53333
6.66667
End of file
五、格式化打印
5.1 printf 命令
gawk中的printf命令和 C语言 中的printf函数一样。
格式:
printf “format string”,var1,var2…
控制字母 | 描述 |
---|---|
c | 数字作为ASCII字符显示 |
d和i | 显示整数值 |
e | 用科学计数法显示数字 |
f | 显示浮点数 |
g | 用科学计数法或浮点数显示(较短的格式有限) |
o | 显示八进制 |
s | 显示字符串 |
x | 显示十六进制 |
X | 显示十六进制,但用大写字母A-F |
#将输入数据当做字符串
$ echo "200.33333"| gawk '{printf "%s\n",$1}'
200.33333
#将输入数据当作小数并保留两位小数
$ echo "200.33333"| gawk '{printf "%2.2f\n",$1}'
200.33
#将输入数据当作整数,并且至少输出5位,不足5位向前补0
$ echo "200.33333"| gawk '{printf "%05d\n",$1}'
00200
六、自定义函数
6.1 定义函数
格式:
function name ([variables])
{
statements
}
6.2 使用函数
使用自定义函数计算平均成绩
$ cat < gawk_cmd
function average(s1,s2,s3)
{
return (s1 + s2 + s3)/3
}
BEGIN {
print "Begin"
}
{
printf "average scores:%.2f\n",average($1,$2,$3)
}
END{
print "End of file"
}
$ gawk -f gawk_cmd data1
Begin
average scores:6.50
average scores:6.53
average scores:6.67
End of file
6.3 函数库
也可以把常用的函数放到一个文件中,封装成函数库。
$ cat < lib_func
function average(s1,s2,s3)
{
return (s1 + s2 + s3)/3
}
$ cat < lib_func
function average(s1,s2,s3)
{
return (s1 + s2 + s3)/3
}
ubuntu@VM-8-14-ubuntu:~$ cat < gawk_cmd
BEGIN {
print "Begin"
}
{
printf "average scores:%.2f\n",average($1,$2,$3)
}
END{
print "End of file"
}
$ gawk -f lib_func -f gawk_cmd data1
Begin
average scores:6.50
average scores:6.53
average scores:6.67
End of file
标签:arr,SHELL,进阶,BEGIN,gawk,cat,print,变量
From: https://blog.csdn.net/weixin_37703001/article/details/140106872