awk语言是什么 - 什么是awk语言 awk语言的最基本功能是在文件或字符串中基于指定规则浏览和抽取信息。awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。 有三种方式调用awk,第一种是命令行方式,如: awk [-F field-sep
awk语言是什么 - 什么是awk语言
awk语言的最基本功能是在文件或字符串中基于指定规则浏览和抽取信息。awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。
有三种方式调用awk,第一种是命令行方式,如:
awk [-F field-separator] 'commands' input-file(s)
这里,commands是真正的awk命令。本章将经常使用这种方法。上面例子中,[ - F域分隔符]是可选的,因为awk使用空格作为缺省的域分隔符,因此如果要浏览域间有空格的文本,不必指定这个选项,但如果要浏览诸如passwd文件,此文件各域以冒号作为分隔符,则必须指明- F选项,如:awk -F: 'commands' input-file
第二种方法是将所有awk命令插入一个文件,并使awk程序可执行,然后用awk命令解释器作为脚本的首行,以便通过键入脚本名称来调用它。
第三种方式是将所有的awk命令插入一个单独文件,然后调用:awk -f awk-script-file input-file(s)
-f选项指明在文件awk_script_file中的awk脚本,input_file(s)是使用awk进行浏览的文件名。
awk执行时,其浏览域标记为$1,$2...$n。这种方法称为域标识。但不要忘了加逗号以分隔域。如果希望打印一个有5个域的记录的所有域可使用$0,意即所有域。
确保用花括号括起动作语句(如print这种动作),用圆括号括起条件语句。正则表达式用斜线//括起来。注意分号的使用,它分隔awk命令。
vi data.f(每列后是tab)
48 Dec 3BC1997 LPSX 68.00 LVX2A 138
483 Sept 5Ap1996 USP 65.00 LVX2C 189
47 Oct 3ZL1998 LPSX 43.00 KVM9D 512
219 dec 2CC1999 CAD 23.00 PLV2C 68
484 nov 7PL1996 CAD 49.00 PLV2C 234
483 may 5PA1998 USP 37.00 KVM9D 644
216 sept 3ZL1998 USP 86.00 KVM9E 234
下面的例子重定向输出到新文件:
awk '{print $0}' data.f > data.f.1
使用t e e命令,在输出到文件的同时输出到屏幕:
awk '{print $0}' data.f | tee data.f.2
打印信息头放置在BEGIN模式部分:
awk 'BEGIN {print "Name Belt\n---------------"}{print $1"\t"$4}' data.f
打印信息尾。E N D语句在所有文本处理动作执行完之后才被执行。E N D语句在脚本中的位置放置在主要动作之后:
awk 'BEGIN {print "Name Belt\n---------------"}{print $1"\t"$4} END {print "end-of-report"}' data.f
为使一域号匹配正则表达式,使用符号‘~’后紧跟正则表达式,也可以用i f语句。awk中i f后面的条件用()括起来。
如果第1域匹配483的话就把该记录打印出来:
awk '{if($1~/483/) print $0}' data.f
完成同一目的也可以这样写:
awk '$0~/483/' data.f
为精确匹配4 8,使用等号= =,并用单引号括起条件:
awk '{if($1=="48") print $0}' data.f
有时要浏览信息并抽取不匹配操作的记录,与~相反的符号是!~,意即不匹配:
awk '{if($1!~/483/) print $0}' data.f
完成同一目的也可以这样写:(缺省情况下, awk将打印所有匹配记录)
awk '$0!~/483/' data.f
为查询大小写信息,可使用[ ]符号。在测试正则表达式时提到可匹配[ ]内任意字符或单词:
awk '/[lL]PSX/' data.f
抽取名字,其记录第3域的第3个字符是L,使用句点.
awk '$3~/^..L/' data.f
使用竖线符|意为匹配| 两边模式之一。注意,使用竖线符时,语句必须用圆括号括起来:
awk '$0~/(USP|LPSX)/' data.f
复合表达式,&& AND,|| OR,!非:
awk '{if($1=="483" && $2~/^Sept/) print $0}' data.f
awk内置变量
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行-F选项
NF 浏览记录的域个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
要快速查看记录个数,应使用NR。print NR放在E N D语法中:
awk 'END {print NR}' data.f
使用NF变量显示每一条读记录中有多少个域,并在END部分打印输入文件名:
awk '{print NR,NF,$0}END{print FILENAME}' data.f
至少存在一个记录后,查询字符串USP,最后打印结果:
awk '{if(NR>0&&$4~/USP/)print$0}' data.f
NF的一个强大功能是将变量$PWD的返回值传入awk并显示其目录。这里需要指定域分隔符/
echo $PWD | awk -F/ '{print $NF}'
设置输入域到域变量名:
awk '{no=$1;month=$2;if(no=="48") print no" month is " month}' data.f
修改数值域取值:
awk '{if($1=="48") $5=$5-10; print $1,$5,$6}' data.f
修改文本域:(要记住实际输入文件是不可修改的,修改的只是保存在缓存里的awk复本。awk会在变量N R或N F变量中反映出修改痕迹。)
awk '{if($2=="Dec") $2="December";print $0}' data.f
只显示修改记录:
awk '{if($2=="Dec") {$2="December";print $0}}' data.f
创建新的输出域:
awk 'BEGIN {print "No\tMonYear"} {if($2~/[Ss]ept/) {$8=$5-$7; print $2,$8}}' data.f
awk 'BEGIN {print "No\tMonYear"} {if($2~/[Ss]ept/) {diff=$5-$7; print $2,diff}}' data.f
列值增加很有用。许多文件都要求统计总数:
awk '(tol+=$5); END {print "Total money:" tol}' data.f
如果文件很大,你只想打印结果部分而不是所有记录,在语句的外面加上大括号{}即可:
awk '{(tol+=$5)}; END {print "Total money:" tol}' data.f
快速查看所有文件的长度及其总和,但要排除子目录:
ls -l | awk '/^[^d]/ {print $9"\t"$5} {tol+=$5} END {print "Total KB:"tol}'
awk内置字符串函数
gsub(r,s) 在整个$0中用s替代r
gsub(r,s,t) 在整个t中用s替代r
index(s,t) 返回s中字符串t的第一位置
length(s) 返回s长度
match(s,r) 测试s是否包含匹配r的字符串
split(s,a,fs) 在fs上将s分成序列a
sprint(fmt,exp) 返回经fmt格式化后的exp
sub(r,s) 用$0中最左边最长的子串代替s
substr(s,p) 返回字符串s中从p开始的后缀部分
substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分
要在整个记录中替换一个字符串为另一个,使用正则表达式格式, /目标模式/,替换模式/
awk 'gsub(/483/,111) {print $0}' data.f
返回目标字符串Bunny中ny出现的第一位置,即字符个数
awk 'BEGIN {print index("Bunny","ny")}'
观察ASCII码中65的等价值。管道输出65到awk。printf进行ASCII码字符转换。这里也加入换行,因为缺省情况下printf不做换行动作:
echo "65" | awk '{printf "%c\n",$0}' 或 awk 'BEGIN {printf "%c\n",65}' 效果一样
整数传入后被加了六个小数点:
awk 'BEGIN {printf "%f\n",999}'
要求名字左对齐,15个字符长度,后跟序列号:
awk '{printf "%-15s%s\n",$2,$1}' data.f
awk脚本文件
脚本从/etc/passwd文件中抽取第1和第5域,通过分号“;”分隔passwd文件域。第1域是帐号名,第5域是帐号所有者。
vi passwd.awk
-------------------------------------------------------------------
#!/bin/awk -f
#to call: passwd.awk /etc/passwd
BEGIN{FS=":"}
{print $1,"\t",$5}
-------------------------------------------------------------------
chmod u+x passwd.awk
passwd.awk /etc/passwd
awk 'END {print FILENAME}' test.txt | awk '{printf "%50s",$1}' >> a.tmp
awk 'END {print NR}' test.txt | awk '{printf "%10s",$1}' >> a.tmp
date "+%Y-%m-%d %H:%M:%S" | awk -F/ '{printf "%20s\n",$1}' >> a.tmp