内建变量
$1, $2, $3 ....
以字段分隔符分割的1,2,3段字段
gawk 数据字段和记录变量
变量 | 描述 |
---|---|
FIELDWIDTHS | 由空格字段分割的一系列数字,定义了每个数据字段的确切宽度 |
FS | 输入字段分隔符 |
OFS | 输出字段分隔符 |
RS | 输入记录分隔符 |
ORS | 输出记录分隔符 |
*默认情况下,gawk
将OFS
设置为一个空格
, RS,ORS
为换行符
# FS OFS
gawk 'BEGIN{FS=","; OFS="-"} {print $1, $2, $3}' data1 #data1-data2-data3
# FIELDWIDTH
# 一旦设定了该值,gawk就会忽略FS的值,并且FIELDWIDTH的值不可再改变
cat data1b #1005.3247596.37
gawk 'BEGIN{FIELDWIDTH="3 5 2 5"}{print $1,$2,$3,$4}' data1b #100 5.324 75 96.37
# RS
cat data2
hhh
name
123
eee
name
456
gawk 'BEGIN{FS="\n"; RS=""} {print $1,$3}' data2
hhh 123
eee 456
更多的gawk内建变量
变量 | 描述 |
---|---|
ARGC | 当前命令行参数个数 |
ARGV | 命令行参数数组 |
ARGIND | 当前文件在ARGV中的位置 |
ENVIRON | 当前shell环境及其值组成的关联数组 |
ERRNO | 读取或关闭输入文件发生错误时的系统错误号 |
FILENAME | gawk输入数据的数据文件的文件名 |
FNR | 当前数据文件中的数据行数 |
NF | 数据文件中的字段总数 |
NR | 已处理的输入记录数 |
RLENGTH | 由match函数所匹配的子字符串长度 |
RSTART | 由match函数所匹配的子字符串的起始位置 |
# 在脚本中引用gawk变量时,变量名前不加美元符
# ARGV ARGC
gawk 'BEGIN{print ARGC,ARGV[1]}' data1 # 2 data1 ; ARGV[0] 是gawk
# ENVIRON
gawk 'BEGIN{print ENVIRON["HOME"]; print ENVIRON["PATH"]}' # 直接打印
# NF
# NF含有数据文件中最后一个字段的数字值,加上美元符则为最后一个字段变量
gawk 'BEGIN{FS=":"; OFS=":"}{print $1,$NF}' /etc/passwd
# FNR NR
# 如果使用一个文件作为输入,FNR和NR的值是相同的;多个文件时,FNR会在处理每个数据文件时重置,NR则会一直累加
gawk 'BEGIN{FS=" "}{print "FNR="FNR,"NR="NR}' data1 data1
FNR=1 NR=1
FNR=2 NR=2
FNR=1 NR=3
FNR=2 NR=4
*
在shell使用gawk时,应该将不同的gawk命令放到不同的行
*
使用同一个gawk脚本时,可以考虑将这段gawk脚本放到一个文件中,使用-f
调用
自定义变量
gawk自定义变量名可以是任意数目字母,数字和下划线,但不能以数字开头,区分大小写
# 在脚本中给变量赋值
gawk 'BEGIN{testing="this is a test"; print testing; testing=11; print testing}'
this is a testing
11
# 赋值语句可以包含数学算式来处理数字值, 求余(%)幂运算符号(^ 或 **)
gawk 'BEGIN{x=3; x = x * 3 + 2; print x}' #11
# 在命令行上给变量赋值
# 使用命令行参数来定义变量时,这个值在代码的begin部分不可用
cat script2.gawk
BEGIN{print "the starting value is",n; FS=" "}
{print $n}
gawk -f script2.gawk n=3 data1 # begin部分不可用n
gawk -v n=3 -f script2.gawk data1 # -v 允许在begin代码之前设定变量
the starting value is 3
data13
data23
data33
处理数组
*
gawk编程语言使用关联数组提供数组功能
*
关联数组与数字数组不同之处在于它的索引值可以是任意文本字符串
# 定义变量
var[index] = element
gawk 'BEGIN{var["hello"]="world"; print var["hello"]}' # world
gawk 'BEGIN{var[1] = 22; var[2] = 33; total=var[1] + var[2]; print total}' # 55
# 遍历数组变量
# 索引值不会按正确的顺序返回,只能保证索引值和数据值相对应
gawk 'BEGIN{
var['a'] = b
var['b'] = c
var['c'] = d
for (i in var)
print "index=",i,"value=",var[i]
delete var['a'] # 删除数组变量,后面无法再用来提取元素值
for (i in var)
print "index=",i,"value=",var[i]
}'
使用模式
BEGIN,END
关键字是用来读取数据流之前或之后执行命令的特殊模式
gawk 'BEGIN{FS=","} /11/{print $1}' data1
匹配含有11的行,并打印第一个字段
**
使用正则表达式时,必须出现在它要控制的程序脚本的左花括号前
# 匹配操作符
# ~ 允许将正则表达式限定在记录中的特定数据字段
gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data1 # data21,data22,data23
gawk -F : '$1 ~ /rich/{print $1,$NF}' /etc/passwd # rich /bin/bash
gawk -F : '$1 !~ /rich/{print $1,$NF}' /etc/passwd # 排除rich的匹配
# 数学表达式
# 数学表达式必须完全匹配 == <= < >= >
gawk -F : '$4 == 0{print $1}' /etc/passwd
gawk -F : '$1 == "data11"{print $1}' data1
结构化命令
# if 语句
# 单行使用else 必须在之前加上分号
gawk '{if ($1 > 20) print $1}' data4
gawk '{if ($1 > 20) {x = $1 * 2; print x}}' data4
gawk '{if ($1 > 20) {x = $1 * 2; print x}; else print $1 / 2}' data4
gawk '{if ($1 > 20) print $1 * 2; else print $1 /2}' data4
# while 语句
gawk '{
total = 0
i = 1
while (i < 4)
{
total += $i
if (i == 2)
break
i++
}
avg = total / 2
print avg
}' data5
# do-while 语句
gawk '{
total = 0
i = 1
do{
total += $i
i++
}while (total < 150)
}' data5
# for语句
gawk '{
total = 0
for (i = 1; i < 4; i++)
total += $i
avg = total / 3
print avg
}' data5
格式化打印
格式化指定符的控制字母
控制字母 | 描述 |
---|---|
c | ASCII字符显示 |
d | 整数值 |
i | 整数值 |
e | 科学计数法显示 |
f | 浮点值 |
g | 科学计数法或浮点值(选择较短的格式) |
o | 八进制值 |
s | 文本字符串 |
x | 十六进制值 |
X | 大写A~F,十六进制值 |
*width
指定输出字段宽度的最小值,右对齐,空格填充,若超过则正常输出
*prec
指定浮点数小数点后的位数,或文本字符串中显示的最大字符数
-
指明左对齐而不是右对齐
# 使用printf需末尾手动添加换行符来生成新行
gawk 'BEGIN{FS='\n', RS=""}{printf "%-16s %s\n", $1, $4}' data2
hhh 123
eeee 123
内建函数
gawk数学函数
函数 | 描述 |
---|---|
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) | 为计算随机数指定一个种子值 |
x=int(10 * rand())
产生大整数随机数
按位操作的函数
函数 | 描述 |
---|---|
and(v1,v2) | 与运算 |
compl(val) | 补运算 |
lshift(val,count) | 左移 |
or(v1, v2) | 或运算 |
rshift(val,count) | 右移 |
xor(v1,v2) | 异或 |
字符串函数
函数 | 描述 |
---|---|
asort(s [,d]) | 数组按照元素值排序,排序后数组存在数组d |
asorti(s [,d]) | 数组s按照索引值排序,排序后数组存在数组d |
gensub(r s h [,t]) | 查找$0或字符串t来匹配正则表达式r |
gsub(r, s [,t]) | 查找$0或字符串t来匹配正则表达式r |
index(s, t) | 返回字符串t在s中的索引值,没有则返回0 |
length([s]) | 返回字符串s的长度,没有则返回$0的长度 |
match(s, r [,a]) | 返回字符串s中正则表达式r出现位置的索引 |
split(s, a [,r]) | 将s用FS字符或正则表达式分开放到数组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中所有字符换成大写 |
[]
内是可填可不填
gawk 'BEGIN{FS=","}{split($0, var); print var[1],var[5]}' data1
将数据字段放到数组中
时间函数
函数 | 描述 |
---|---|
mktime(datespec) | 将一个YYYY MM DD HH MM SS[DST]格式指定的日期转换为时间戳 |
strftime(format [, timestamp]) | 将当前的时间戳转化为格式日期 date() |
systime() | 返回当前时间的时间戳 |
gawk 'BEGIN{date = systime(); day = strftime("%A, %B, %d, %Y", date); print day}'
自定义函数
# 自己定义的函数,必须用function函数关键字
# 函数名唯一标志函数
# 自定义函数必须出现在所有代码块之前(包括BEGIN代码块)
gawk '
function myprint()
{
printf "%-16s - %s\n", $1, $4
}
BEGIN{FS="\n"; RS=""}
{
myprint();
}' data2
# result
hhhh 123
eee 456
# 创建函数库
cat funclib
function myrand(limit)
{
return int($1 * limit * rand())
}
cat script4
BEGIN{FS="\n"; RS=""}
{
myrand(1)
}
gawk -f funclib -f script4 data2 # 调用
实例
cat scores.txt
rich blum,team1,100,115,95
barbara blum,team1,110,115,100
christine bresnahan,team2,120,115,118
tim bresnahan,team2,125,112,116
# 计算每个队伍的总分和平均分
# !/bin/bash
for team in $(gawk -F ',' '{print $2}' scores.txt | uniq) # team1 team2
do
gawk -v team=$team '
BEGIN{FS=","; total = 0}
{
if ($2 == team)
total = $3 + $4 + $5
}
END{avg = total / 6; print team" total score is ",total , "avg is ", avg}
' scores.txt
done