一、awk简介:
在之前的博客中分别介绍了Linux下文本处理三剑客中的grep(文本过滤器)和sed(行编辑器)。
awk被称为报告生成器,其名称来自于三位创世人的姓氏首字母;AWK提供了极其强大的功能,可以进行正则表达式的匹配,样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上AWK的确拥有自己的语言,即AWK程序设计语言,被定义为“样式扫描和处理语言”。它允许创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
常见的awk主要有三种:
awk:旧版本的awk,部分系统仍存在此版本的awk,但通常为oawk(old awk)命令;
nawk:new awk,是awk的升级版;
gawk:gnu awk,是开源实现的awk,早期gawk是旧版awk的替代程序,但是随着不断的更新,也包含了nawk的特性;
在Linux下awk以符号链接的方式链接到gawk,以方便用户的使用;
awk工作流程:
通过模式匹配,逐行读取匹配到的行,根据指定的分隔符(默认为空格),将读取到的一行内容分割成为字段,然后根据指定格式,格式化输出指定字段;
二、用法详解:
基本语法:
# awk[options] 'program' file file ...
# awk[options] 'PATTERN{action}' file file ...
option:
-F CHAR:指定输入分隔符
-v var_name=VALUE:自定义变量赋值;
模式:
1)、Regexp:正则表达式,格式为/PATTERN/,仅处理被/PATTERN/匹配到的行;
2)、Expression:表达式,其结果为非0或非空字符串时满足条件,仅处理满足条件的行;
3)、Ranges:行范围,此前地址定界,startline,endline,仅处理范围内的行;
4)、BEGIN/END:特殊模式,仅在awk命令的program运行之前(BEGIN)或运行之后(END)执行一次;
5)、Empty:空模式,匹配任意行;
常用的action:
1)、Expressions:表达式;
2)、Controlstatements:控制语句;
3)、Compoundstatements:复合语句;
4)、inputstatements:输入语句;
5)、outputstatements:输出语句;
输出:
print item1,item2,...
1)、各项目之间使用逗号分隔,而输出时则使用输出分隔符分隔;
2)、输出的各item可以字符串或数值、当前记录的字段、变量或awk的表达式;数值会被隐式转换为字符串后输出;
3)、print后面item如果省略,相当于print$0;输出空白,使用pirnt "";
示例:
显示当前系统所有用户和使用的shell;
# awk -F: '{print $1,$7}' /etc/passwd
变量:
注意:引用变量的值,不需要以$开头,所有以$开头的变量,是用于引用字段的值;
1)、内置变量
FS:FieldSeperator,输入时的字段分隔符;
RS:RecordSeperator,输出行分隔符;
OFS:Output FieldSeperator,输出时的字段分隔符;
ORS:Outpput RowSeperator,输出时的行分隔符;
NF:Numbers ofField,字段数;
NR:Numbers ofRecord,行数;所有文件的一并计数;
FNR:行数;各文件分别计数;
ARGV:数组,保存命令本身这个字符,awk '{print $0}' 1.txt 2.txt,意味着ARGV[0]保存awk
ARGC:保存awk命令中参数的个数;
FILENAME:awk正在处理的当前文件的名称;
2)、可自定义变量:
选项:
-v var_name=VALUE
变量名区分字符大小写;
(1)、可以program中定义变量;
(2)、可以命令行中通过-v选项自定义变量;
示例:
# awk'BEGIN{FS=":";OFS="##";a="shell is"}{print$1,a,$NF}' /etc/passwd
printf命令:
命令的使用格式:
printf format, item1, item2,...
要点:
1)、要指定format;
2)、不会自动换行;如需换行则需要给出\n;
3)、format用于为后面的每个item指定其输出格式;
format格式的指示符都%开头,后跟一个字符:
%c:显示字符的ASCII码;
%d,%i:十进制整数;
%e,%E:科学计数法显示数值;
%f:显示浮点数;
%g,%G:以科学计数法格式或浮点数格式显示数值;
%s:显示字符串;
%u:显示无符号整数;
%%:显示%自身;
修饰符:
#:显示宽度
-:左对齐
+:显示数值的符号
.#: 取值精度
#表示为数字;
示例:
# awk 'BEGIN{FS=":"}{printf "%-15s %-15s;\n",$1,$7}' /etc/passwd
输出重定向:
print items> output-file
print items>> output-file
print items| command
特殊文件描述符:
/dev/stdin:标准输入
/dev/stdout:标准输出
/dev/stderr:错误输出
示例:
# awk '{print FNR,$0 > "/tmp/test"}' /etc/issue /etc/fstab
操作符:
算术操作符:
x+y
x-y
x*y
x/y
x**y、x^y
x%y
-x:负值
+x:转换为数值
字符串操作符:连接
赋值操作符:
=
+=
-=
*=
/=
%=
^=(**=)
++
--
如果模式自身是=号,要写为/=/
比较操作符:
<
<=
>
>=
==
!=
~:模式匹配,左边的字符串能够被右边的模式所匹配为真,否则为假;
!~:
逻辑操作符:
&&:与
||:或
条件表达式:
selector?if-true-expression:if-false-expression
函数调用:
function_name(argu1,argu2)
示例:
判断用户类型;
# awk 'BEGIN{FS=":";OFS=";"}{$3>=500?utype="commonuser":utype="admin or system user";print $1,"is",utype}' /etc/passwd
控制语句:
1)、if…else:
格式:if (condition){then body} else {else body}
示例:
显示字段数大于等于8的行;
# awk '{if (NF>=8){print}}' /etc/inittab
判断用户类型;
# awk 'BEGIN{FS=":";a="is an admin or system user";b="is acommon user"}{if($3>=500){print $1,b}else{print $1,a}}' /etc/passwd
2)、while
格式:while (condition){while body}
示例:
显示奇数行;
# awk '{i=1;while (i<=NF){printf "%s ",$i;i+=2};print ""}' /etc/inittab
显示字段数大于等于6的行;
# awk '{i=1;while (i<=NF){if (length($i)>=6) {print $i}; i++}}' /etc/inittab
length()函数:取字符串的长度
3)、do…while循环:
格式:do {do-while body}while (condition)
示例:
计算1到100之和;
# awk 'BEGIN{sum=0;i=0;do{sum+=i;i++}while(i<101)print sum}'
4)、for循环:
格式:for (variableassignment; condition; iteration process) {for body}
示例:
显示奇数行;
# awk '{for(i=1;i<=NF;i+=2){printf "%s",$i};print ""}' /etc/inittab
显示字段数大于等于6的行;
# awk '{for(i=1;i<=NF;i++){if(length($i)>=6)print $i}}' /etc/inittab
for循环可用来遍历数组元素:
语法:for (i in array){for body}
5)、case语句:
语法:switch(expression) {case VALUE or /RGEEXP/: statement1;... default: stementN}
6)、循环控制
break
continue
7)、next:
提前结束对本行的处理进而进入下一行的处理;
示例:
显示uid为基数的用户:
# awk 'BEGIN{FS=":"}{if($3%2==0)next;print $1,$3}' /etc/passwd
显示位于奇数行的用户:
# awk 'BEGIN{FS=":"}{if(NR%2==0)next;print NR,$1}' /etc/passwd
数组:
关联数组:
array[index-expression]
index-expression:可以使用任意字符串; 如果某数组元素事先不存在,那么在引用时,awk会自动创建此元素并将其初始化为空串;因此,要判断某数组是否存在某元素,必须使用“index in array”这种格式;
A[first]="helloawk"
printA[second]
要遍历数组中的每一个元素,需要使用如下特殊结构:
for (var inarray) {for body}
其var会遍历array的索引;
state[LISTEN]++
state[ESTABLISHED]++
示例:
统计当前主机每一种网络连接出现的次数;
# netstat -tan | awk '/^tcp/{++state[$NF]}END{for(s in state){print s,state[s]}}'
删除数组元素:
deletearray[index]
内置函数:
split(string,array[,fieldsep[,seps]])
功能:将string表示的字符串以fieldsep为分隔符进行切片,并切片后的结果保存至array为名的数组中;数组下标从1开始;
root:x:0:0::/root:/bin/bash
user[1]="root",user[2]
此函数有返回值,返回值为切片后的元素的个数;
示例:
显示连接请求的IP;
# netstat -tn | awk '/^tcp/{lens=split($5,client,":");ip[client[lens-1]]++}END{for (i inip) print i,ip[i]}'
length(string)
功能:返回给定字串的长度
substr(string,start[,length])
功能:从string中取子串,从start为起始位置为取length长度的子串
system(command)
功能:执行系统command并将结果返回至awk命令
systime()
功能:systime函数返回从1970年1月1日开始到当前时间(不计闰年)的整秒数
tolower(s)
功能:将s中的所有字母转为小写
toupper(s)
功能:将s中的所有字母转为大写
结语:
awk的用法介绍到这里,此文仅是部分常见用法,有兴趣可深入研究;以上为本人学习整理内容,如有遗漏和失误,欢迎各路大神来喷。
本文出自 “小马的学习记录” 博客,请务必保留此出处http://masachencer.blog.51cto.com/8683770/1698311