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) | 小写转换为大写 |
输出函数 | |
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; # 中间必须加逗号不然出错
}