AWK的基本使用

博客原文链接
说明上述博客也是本人的博客

在awk中使用变量

awk命令中允许使用变量。内置变量:通常用于控制输出和保存“awk”当前工作状态。自定义变量:用户自己定义使用,通常放到BEGIN语句中初始化(赋值)。awk不能确定自定义变量的类型,通常将其默认为字符串进行处理。

内置变量

常用内置变量:

  • FILENAME: 用于保存输入文件名称。
  • NF: 用于保存当前正在处理记录的域个数。
  • NR:用于保存从文本中都去记录的个数。
  • FNR:用于保存当前读取的记录数。输入文件为多个的时候,awk重置此变量。
  • OFS:用于设置输出分隔字符字符,默认空格。
  • FS:用于设置字段分隔符。
  • ORS:用于设置输出记录分隔符,默认为新的一行。
  • RS:用于设置记录分隔符,默认为新行。
  • OFMT:数字的输出格式。
  • ENVIRON:读取环境变量。

1.输出文本格式化,使用内置变量OFS和ORS。

# 使用手动设置分隔符,以/etc/passwd文件为例
# awk 'BEGIN{FS=":"; print "username\tShell"} {print NF,NR,$1"\t\t"$7}END{print FILENAME}' /etc/passwd

2.处理含有特殊分隔符的文本

分隔符为"#",以空格为分割分输出第一列、第二列(文件名为`students3`)
2821020225#iulu#Sichuan#Lixia#01/23/93#89#76#88#72#325#81
2821020115#iumin#Henan#lixia#05/14/94#78#65#59#78#280#70
2721010321#uli#Jiangsu#Luolei#12/25/92#76#81#85#79#321#80
# 使用FS重新设置重新读取时的域分隔符,使用RS重新设置记录分隔符
# awk 'BEGIN{FS="#"; RS="\\n\n"} {print $1, $2}' students3

3.使用OFMT设置浮点数输出格式

# awk 'BEGIN{OFMT="%.2F"; print 20.123456}'

4.引用环境变量

# 使用内置变量ENVIRON读取系统的环境变量
# awk 'END{print ENVIRON["LANG"]}' students3

自定义变量

自定义变量通常用于统计并计算某个数字字段的结果,也可用于引用字符串。下面举例说明:
1.统计当前文件夹中所有文件占用的空间

# 从ls -l中读取文件大小,使用自定义变量统计所占空间
# ls -l | awk 'BEGIN{A=0} {A+=$5} END{print "The size of all files in current directory is: "A}'

2.在动作语句之后添加变量

# 变量先使用后定义
# awk '$3 == NAME {print $0}' NAME="Sichuan" students.dat
# awk '($3 == NAME) {print $0}' NAME = "Sichuan" students.dat (此时出现错误,awk: cannot open NAME (No such file or directory)。
所以自定义变量名和值之间`=`两边不要加空格)

在awk中使用流程控制

awk中有类似C语言的流程控制语句:if、while、do-while、for语句。此外还提供四个语句控制循环的执行过程(continue,break,next和exit)。

循环控制语句(类似C语言的语句这里暂不介绍)

  • next:使awk读取文本的下一行。
  • exit:若此语句没有出现在END表达式中,则立即跳转执行END中的语句。如果出现在END中则awk命令停止执行并退出。

使用示例

1.if语句(针对文件students.dat)

# 输出文件中总成绩在300分以上的学生的id,name,和分数(设置分隔符为\t):
# awk 'BEGIN{OFS="\t"} {if($10 >= 300) print $1, $3, $10}' students.dat
# if判断中使用路基运算符
# awk 'BEGIN{OFS="\t"} {if($10 >= 300 && $3=="Jiangsu") print $1, $3, $10}' students.dat

2.计算指定文件夹下文件大小和文件夹的个数:

# 说明:可以根据ping命令输出格式自行更改含有$符合的行。
BEGIN{
	# 在BEGIN中初始化变量
	A = 0;
	count = 0;
}
{
	# 如果域1第一个字符为-,则将域5的值与变量A相加
	if($1 ~/^-/)
		A += $5;
	if ($1 ~/^d/)
		++count;
}
# 在END表达式中输出计算结果
END{
	print "total:"A;
	# 输出文件夹总数,注意当前目录和上级目录
	print count-2, "directories.";
}
# 使用示例
# ls -al /etc | awk -f total.awk

3.使用ping测试链接并统计延时

# ping.awk
BEGIN{
	# 重新定义分隔符=和空格
	FS="[= ]";
	# 初始化变量ACG, MAX和MIN
	AVG = 0;
	MAX = 0;
	MIN = 0;
}
{
	# 设置执行次数
	for(I = 1; I < 9; ++I) {
		if(NR == 2) {
			MAX = $11;
			MIN = $11;
			IP_ADDR=$5;
		}
		if (NR >1 && NR < 6) # 统计第2,3,4,5次 {
			AVG+=$11;
			if($11 > MAX)
				MAX = $11;
			if($11 < MIN)
				MIN = $11;
		}
		if(NR > 6) # NR为6时,跳出循环执行END
			exit;
    }
}
END{
	AVG/=4;
	print "IP address:", IP_ADDR;
	print "AVG:",AVG,"ms";
	print "MAX:",MAX,"ms";
	print "MIN:",MIN,"ms";
}
# 代码使用示例
# ping -c4 localhost | awk -f ping.awk

awk命令中的函数

awk命令中的函数分为:内置函数和用户自定义函数。内置函数是一些用来处理字符串和数学运算的函数,用户自定义函数执行自定义的功能。

常见内置函数

函数 说明
sub(regexp, replacement [, target]) 当模式regexp第一次出现时,用replacement替换
gsub(regexp, replacement [, target]) 将与模式regexp匹配的内容全部用replacement替换
index(string, find) 返回与find匹配的字符串,第一次在string中出现的位置
length([string]) 返回字符串string的长度
match(string, regexp [, array]) 返回与regexp字符串第一次相匹配的位置。如果不存在则返回0
split(string, array [, fieldsep]) 返回字符串数组元素个数
printf(format, expr1 [, expr2, ...]) 格式化输出函数
substr(string, start [, length]) 从string中返回从start开始,长度为length的子串
tolower(string) 大写转换为小写
toupper(string) 小写转换为大写
print 输出函数
rand() 返回一个0到1之间的随机数
system() 将传递来的字符串按shell命令执行
atan2(x, y) 四象限的反正切函数
sin(x)、cos(x)、log(x)、exp(x)、int(x)、sqrt(x) 正弦、余弦、自然对数、E的x次幂、转换为整数、开平方

示例数据

# 数据students2,tab键分割
20140322	Lixiao	0	A	B	0
20140422	Xiaobai	B	C	0	0
20130222	Bobo	0	0	0	0
20130831	Juzhu	B	C	A	A

1.sub函数

# 使用sub函数修改记录
# awk '$1 ~/201403/{print sub(/Lixiao/, "Liming", $0)"\n"$0}' students2

2.gsub函数

# 使用gsub函数替换所有A为95,并打印一共替换了多少个
# awk 'BEGIN{N=0}{N+=gsub(/A/, "95", $0); print $0} END{print N}' students2
# BEGIN语句和执行语句{}之间可以添加过滤条件,如下只显示id中包含2014的学生信息:
# awk 'BEGIN{N=0}$1 ~/2014/{N+=gsub(/A/, "95", $0); print $0} END{print N}' students2

3.index函数返回第一次匹配成功的位置

# 找出第一个X出现的位置后退出awk
# awk '{N=index($0, "X"); if(N==0) next; else{ print N, $0; exit}}' students2

4.split函数拆分字符串

# split将字符串拆分,然后存入数组ARR。然后使用for循环输出。awk中的数组可以不用定义也不用指出其元素的个数。
# awk 'BEGIN{print split("ACED-3214-ifoj-ED90-9IMK", ARR, "-");  for(I in ARR) print ARR[I]}'

5.printf函数

# 使用printf函数可以进行格式控制,与C语言的printf函数一样。
# awk 'BEGIN{A=100; printf "%c\n%o\n%x\n", A, A, A}'

用户自定义函数

用户自定义函数作用是全局的,函数中定义的变量只作用于函数内部。可以使用return返回一个值。
基本格式:

function name([参数列表])
{
    语句块;
    [return ..];
}

1.计算学生的总成绩和平均成绩

# 计算总成绩
function totle_score(A, B, C, D) {
	return A+B+C+D;
}
function avg_score(A,B,C,D) {
	return (A+B+C+D)/4;
}
{
	printf "%-10s\t%d\t%d\t%d\t%d\t%d\t%g\n",$4,$6,$7,$8,$9,totle_score($6,$7,$8,$9), avg_score($6,$7,$8,$9);
}
END{
	printf "%s\n", FILENAME; # 中间必须加逗号不然出错
}
posted @ 2014-08-02 15:29  mykelia  阅读(381)  评论(2编辑  收藏  举报