作者: 赵燕燕
(一)AWK:
Linux下有很多基于文本的样式扫描和处理的工具,他们可以实现以文档的列或行为单位进行扫描处理,大大减轻了文本处理的工作量, 这样的命令包括sed, grep, sort以及find等等,awk是其中很优秀的一种。他的功能大大强于sed和grep.它不仅可以完成grep和sed所能完成的全部工作,还可以进行样式装入,流控制,数学运算,进程控制甚至变量和函数。awk不仅是一条命令,更是一种语言。
awk特别适合于重新格式化数据文件,它可以将输入数据分成若干个记录,每个记录可以分成以特定分割符分开的域,这样对于任何域都可以灵活的操作处理。 而且awk的语法又和shell与C有很多相似之处,便于学习。
下面的章节就简单得从变量, 命令格式,子函数等几个方面详细的介绍下awk.
(二)AWK的格式:
awk Option ' 'BIGIN' {动作语法} {动作语法} 'END' {动作语法}' file1 file2 … |
1) Option:
Option指的是awk执行单引号部分之前进行的操作
-f: 运行awk文件
例如:awk -f filename
-F: 设置分隔符,
例如,设置分割符为 “|”
awk –F “|” ‘{print $1}’ filename
-v: 特殊操作,需要在执行单引号部分之前就执行的
例如,传递shell参数:awk -v var=$b '{print var, $var}' filename
2) BEGIN:
BEGIN是要在执行行处理之前就执行的,执行的动作用{}括起来。注意,此处awk并没有读入文档,也不知道要处理的文档的名字信息,关于文档的变量都被设置为null
3)END:
END是要在执行行处理之后执行的,所有变量的值都和处理完文档的值保持一致。执行的动作用{}括起来
4)行处理的动作:
行处理的动作夹在BEGIN{}和END{}之间, 可以包括模式匹配和行处理动作。 其中行处理动作要用{}括起来。模式匹配不包含在{}之中。
模式匹配:支持正则表达式的匹配
例如:awk ‘/^8*/’ file
awk ‘$2 >5 && $2<=15’ file
awk '$1 ~ /101/ {print $1}' file 匹配后执行动作
awk '$1>2 {print $1,$2}' file匹配后执行动作
行处理动作:包括字符串操作,数字操作等等。
而且数字操作可以实现数字和字符串的直接运算。
例如:awk -v s=123 '{n = 0 + s; print n}' filename
如果字符串不是以数字开头的,例如sads222, 就直接默认为这个变量为0。
如果字符串以数字开头,例如233asd,就直接截取数字的部分。
行处理动作的awk语法中循环,判断,输出等都与C语言很接近。这也是awk受到欢迎的一个原因。
例如: 找到以|分隔的test.txt文件中的第一列是以8开头的行数
awk -F | ''BEGIN'{d=0} /$1~^8/{d++} 'END'{print d}' filename
单引号的部分都可以完全放入到.awk的文件中
上面的命令行的例子,同样可以在文件中实现:
例如:可以编写file.awk:
BEGIN {d=0}
/$1~^8/{d++}
END {print d}
运行awk命令: awk -f file.awk test.txt
(三)AWK的变量:
1) 内置变量:
像shell语言一样,awk有一些内置变量。 这些变量使用户可以方便的控制想要获取的文件的属性信息:
$1, $2....处理行的第一列,第二列...
$0处理行的所有列
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览的文件名
FS 设置输入域分隔符,等价于命令行-F选项
NF 浏览记录的域个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
例如:打印域的个数,已读的记录数,整行信息,第一个参数(0的话是全部)及用户(最后一个是取得系统的环境变量)
awk -F '#' '{print NF,NR,$0,ARGV[1],ENVIRON["USER"]}' test.txt
2) 变量
变量的表示基本与shell保持一致。任何定义的变量不需要初始化,awk会根据第一次定义的数值,确定类型。
3) 输入输出
输入:awk '/^8/{"echo '$1'"|getline d; print d}' test.txt
awk ‘BEGIN {“date”|getline d; print d}'
echo aaas | awk '{print $1}'
其他的awk引用外部变量的几种方法:
a. awk –v awkvar=$extvar…#使外部变量的作用域扩展到BEGIN{}
b. awk '<awk expression>' "awkvar=$extvar" filename #BEGIN段不可用
c. 在awk表达式中使用'$extvar'
d. 模式引用(在正则表达式中引用外部变量) '"$extvar"
e. 遍历外部数组(用于BEGIN段处理) awk 'BEGIN{for(i=1;i<ARGC;i++)print ARGV[i]}' ${extarr[@]}
f. 引用环境变量 ENVIRON["environment variable"]
例如:awk中引用shell的变量 export变量,然后用ENVIRON[“var”] 使用" " awk '{print awkvar}' "awkvar=$var" filename 使用' ' awk '{print '$var'}' filename |
例如:Shell中使用awk传递出来的变量 eval $(awk 'BEGIN{print "var1=along;var2=test"}') |
输出:print, echo,重定向...
(四)子函数
子函数的定义与C, C++等其他的语言的定义是一致的 :
例如一个awk可以写成: function gcd(x, y) { x = int(x) y = int(y) print x,y r = x % y return (r == 0)? y : gcd(y, r) } BEGIN {print "BEGIN"} {g = gcd($1, $2); print "gcd("$1" ,"$2") =",g} END {print "END"}
|
避免变量污染,可以在子函数中使用局部变量。例子中function factorial(n, i)的i就是在定义局部变量,n是从主函数中传递过来的值。
function factorial(n, i) { s=1; for (i=1; i<=n; i++) { s*=i; } return s; } { for (i=1;i<=10;i++) { value=factorial(i); printf("fac(%d)=%d/n",i,value); } } |
同样可以这样定义: function factorial(n, _ARGVEND_, i), 其中的_ARGVEND_的表示正常的调用所需要的形参到此结束。后面的假形参只是局部变量的定义。
(五)调试
Awk可以简单的作为单条的命令并结合输入输出,进行调试。
另外,如果想要查看运行中调试全局变量, 可以使用-dump-variables 参数。 例如调用上面的文件:echo "" | awk -f fac.awk --dump-variables=/tmp/var.dump
查看var.dump文件,就会把所有的属性信息,变量信息打印出来
ARGC: number (1)
ARGIND: number (0)
ARGV: array, 1 elements
BINMODE: number (0)
CONVFMT: string ("%.6g")
ERRNO: number (0)
FIELDWIDTHS: string ("")
FILENAME: string ("-")
FNR: number (1)
FS: string (" ")
IGNORECASE: number (0)
LINT: number (0)
NF: number (0)
NR: number (1)
OFMT: string ("%.6g")
OFS: string (" ")
ORS: string ("/n")
RLENGTH: number (0)
RS: string ("/n")
RSTART: number (0)
RT: string ("/n")
SUBSEP: string ("/034")
TEXTDOMAIN: string ("messages")
i: number (11)
s: number (3628800)
value: number (3628800)