Linux命令行与shell脚本编程大全笔记(gawk进阶)

内建变量
$1, $2, $3 .... 以字段分隔符分割的1,2,3段字段

gawk 数据字段和记录变量

变量描述
FIELDWIDTHS由空格字段分割的一系列数字,定义了每个数据字段的确切宽度
FS输入字段分隔符
OFS输出字段分隔符
RS输入记录分隔符
ORS输出记录分隔符

*默认情况下,gawkOFS设置为一个空格, 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读取或关闭输入文件发生错误时的系统错误号
FILENAMEgawk输入数据的数据文件的文件名
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

格式化打印
格式化指定符的控制字母

控制字母描述
cASCII字符显示
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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值