标签:文本三剑客awk awk循环 awk控制语句 awk数组 awk函数
一、AWK介绍 Linux文本处理工具三剑客:grep、sed和AWK。其中grep是一种文本过滤工具,sed是文本行编辑器,而AWK是一种报表生成器,就是对文件进行格式化处理,这里的格式化不是文件系统的格式化,而是对文件内容进行各种“排版”,进而格式化显示
在Linux之上我们使用的GUN awk ,简称gawk,并且gawk其实awk的链接文件,因此在系统上使用awk和gawk都是一样的。我们通过mangawk可以获得gawk的相关功能说明----------- gawk-pattern scanning and processing language(模式扫描及各种处理语言),gawk是一种过程式编程语言,gawk还支持条件判断,数组、循环等各种编程语言中所有可以使用的功能,因此我们还可以吧gawk称为一种监本语言解释器。
awk 在处理文本时也是一次读取一行文本,文件的每一行称为记录,由分隔符分隔的字段(域)标记为$1,$2...$n,称为域标识,$0为所有域,和shell中变量$符含义不同,然后根据输入分隔符(默认为空格字符)进行切片,切成n段,然后将每一片都赋予awk内部的一个变量当中这些$1,$2等等一直到最后一个,awk就可以对这些片段进行处理,比如某一段、特定段,比如计数、运算等
#awk
# awk -f /PATH/AWK_SCRIPT
#!/bin/awk -f
awk [option] ‘program’ file1 file2
Option:选项
-F[] :指明输入时用到的字段分隔符,例:-F:
-v var=value: 自定义变量,例:-v var=123
-f /PATH/AWK_SCRIPT:指定awk程序的文件
Program:prattern{action statements;}
awk编程语言,通常由BEGIN语句块、能够使用模式匹配的通用语句块、END,共3部分组成。Program通常是被单引号或双引号中
parttern部分决定动作语句何时触发及触发事件
BEGIN:在读取文件之前执行
END:在读取文件之后执行
Action statements:动作语句,可以是由多个语句组成,各语句之间使用分号分隔“;”
print:换行打印
printf:不换行打印
第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这 个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个 可选的语句块,比如变量初始化、打印输出表格的表头等语句通常 可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,比如 打印所有行的分析结果这类信息汇总都是在END语句块中完成,它 也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。如果 没有提供pattern语句块,则默认执行{ print },即打印每一个读取 到的行,awk读取的每一行都会执行该语句块
变量:内置变量和自定义变量
FS:输入字段分隔符,默认为空白字符
awk -v FS=‘:‘ ‘{print $1,FS,$3}’ /etc/passwd
awk –F: ‘{print $1,$3,$7}’ /etc/passwd
OFS:输出字段分隔符,默认为空白字符
awk -v FS=‘:’ -v OFS=‘:’ ‘{print $1,$3,$7}’ /etc/passwd
RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效
awk -v RS=‘ ‘ ‘{print }’ /etc/passwd
ORS:输出时的行分隔符,默认为换行符
awk -v RS=‘ ‘ -v ORS=‘###‘‘{print }’ /etc/passwd
NF:字段数量,当前行的字段数
awk -F: ‘{print NF}’ /etc/fstab,显示当前行的字段数
awk -F: ‘{print $(NF-1)}‘ /etc/passwd 显示当前行的第NF个字段
NR:显示行数;命令后跟的所有文件将统一合并计数
awk ‘{print NR}‘ /etc/fstab
awk END‘{print NR}‘ /etc/fstab
FNR:显示行号;各文件分别计数,行号
awk ‘{print FNR}‘ /etc/fstab /etc/inittab
FILENAME:显示当前文件名
awk ‘{print FILENAME}’ /etc/fstab
ARGC:命令行参数的个数
awk ‘{print ARGC}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
ARGV:数组,保存的是命令行所给定的各参数
awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab
注意:当引用这些内置变量时,不用加$;使用ARGC和ARGV时,后面可以是文件名,也可以是a b c d 任意值,不管是文件名或是任意字符串,以空格相隔,每一个值都会被赋值给ARGC这个数组的不同下标,默认从0开始,awk也是一个参数,awk是固定的被赋值给了ARGV[0],后面的所有参数按顺序分配给各个下标,
例:1.这个命令即是打印出这个参数的个数,加上awk本身总共5个
2.显示各个参数的值
自定义变量是区分字符大小写的,自定义变量有两种方法:
例: awk -v test=‘hello gawk‘ ‘{print test}‘ /etc/fstab
awk -v test=‘hello gawk‘ ‘BEGIN{print test}‘
awk ‘BEGIN{test="hello,gawk";print test}‘
awk –F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd
用-v选项和在program中定义的变量的区别,使用-v定义的变量,只有第一次执行的时候会读取一次,在后面的program中弱势变量值发生变化,便不可再回到初值,而program中的命令是每读取一行的时候就会被执行一次,所以,当每读取完一行的时候都会再次被赋值为最初的那个值,所以可以根据自己的需求来选择怎么定义变量,在调用这些变量的值的时候不需要加$,所以如果要输出一些字符串的时候,需要用上引号引起来,否则系统则会认为是要调用变量名为这串字符串的变量的值,
print格式 print item1,item2...
awk ‘{print "hello world"}‘ 显示字符串hello world
awk -F: ‘{print}‘ /etc/passwd 显示/etc/passwd文件中的所有内容
awk -F: ‘{print "wang"}‘ /etc/passwd 每读取/etc/passwd文件中一行内容输出一次字符串“wang”
awk -F: ‘{print $1}‘ /etc/passwd 每读取一行,就截取以“:”为分隔符的第一个字段
awk -F: ‘{print $0}‘ /etc/passwd 显示/etc/passwd文件中每一行以“:”分隔的所有字段(等同于awk -F: ‘{print}‘ /etc/passwd)
awk -F: ‘{print$1"\t"$3}‘ /etc/passwd 输出/etc/passwd每行第1和第3字段,中间以tab分隔
tail -3 /etc/fatab |awk’{print $1,$4}’ 显示/etc/fstab中最后3行的第1字段和第4字段
printf “FORMAT” ,item1,item2...
输出格式符(FORMAT):与item一一对应
%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%: 显示%自身
修饰符:每一种格式符都有一些修饰符
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
-: 左对齐(默认右对齐) %-15s
+:显示数值的正负符号 %+d
示例:
awk -F: ‘{printf "%s",$1}’ /etc/passwd
awk -F: ‘{printf "%s\n",$1}’ /etc/passwd
awk -F: ‘{printf "%-20s %10d\n",$1,$3}‘ /etc/passwd
awk -F: ‘{printf "Username: %s\n",$1}’ /etc/passwd
awk -F: ‘{printf “Username: %s,UID:%d\n",$1,$3}’ /etc/passwd
awk -F: ‘{printf "Username: %15s,UID:%d\n",$1,$3}’ /etc/passwd
awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd
算数操作符:
x+y:加;
x-y:减;
x*y:乘;
x/y:除;
x^y:次方;
x%y:取余;x除以y得出的余数
-x:转换为负值,
+x转换为数值
字符串操作符:没有符号的操作符,字符串连接
赋值操作符:
=:等于;
+=:自加;例,x+=y,意思是把x本身的值加上y的值再赋给x
-=: 自减;例,x-=y,意思是把x减去y的值再赋值给x
*=: 自乘;例,x*=y,意思是把x乘以y的值再赋值给x
/=: 自除;例,x/=y,意思是把x除以y的值再赋值给x
%=:取余赋值;例,x%=y,意思是x除以y后的余数赋值给x
^=: 次方;例,x^=y,意思是把x的y次方的值再赋值给x
++:递加;例,i++,意思是把i的值加1再赋值给i,等同于i+=1
- -: 递减;例,i- -,意思是把i的值减1再赋值给i,等同于i-=1
比较操作符:
= =: 等于
!=: 不等于
\>: 大于
\>=: 大于等于
<: 小于
<= : 小于等于
模式匹配符:
~:左边是否匹配包含右边
!~: 是否左边和右边是否不匹配包含
逻辑操作符:与&&;或||;非!
示例:
awk –F: ‘$0 ~ /root/{print $1}‘ /etc/passwd
awk ‘$0~“^root"‘ /etc/passwd
awk ‘$0 !~ /root/‘ /etc/passwd
awk –F: ‘$3==0’ /etc/passwd
awk –F: ‘$3\>=0 && $3\<=1000 {print $1}‘ /etc/passwd
awk -F: ‘$3==0 || $3\>=1000 {print $1}‘ /etc/passwd
awk -F: ‘!($3==0) {print $1}‘ /etc/passwd
awk -F: ‘!($3\>=500) {print $3}’ /etc/passwd
函数调用:function_name(argu1,argu2...)
条件表达式(三目表达式):
格式: selector?if-true-expression:if-false-expression
三目表达式顾名思义就是有三个表达式组成的,问号之前的表达式通常为判断表达式,问号之后的表达式是满足条件才会执行的语句,冒号之后的是当不满足条件时才会执行的语句。
示例:
awk -F: ‘{$3>=1000?usertype="common user":usertype="sysadmin or sysuser";printf "%15s: %-s\n" ,$1,usertype}‘ /etc/passwd
PATTERN:根据pattern条件,过滤匹配的行,再做处理
awk ‘/^UUID/{print $1}‘ /etc/fstab
awk ‘!/^UUID/{print $1}‘ /etc/fstab
真:结果为非0值,非空字符串
假:结果为空字符串或0值
示例:
awk -F: ‘i=1;j=1{print i,j}‘ /etc/passwd
awk ‘!0’ /etc/passwd
awk ‘!1’ /etc/passwd
awk –F: ‘$3\>=1000{print $1,$3}‘ /etc/passwd
awk -F: ‘$3\<1000{print $1,$3}‘ /etc/passwd
awk -F: ‘$NF=="/bin/bash"{print $1,$NF}‘ /etc/passwd
awk -F: ‘$NF ~ /bash$/{print $1,$NF}‘ /etc/passwd
Startline,endline:/pat1/,/pat2/不支持直接给出数字格式
示例:
awk -F: ‘/^\<root\>./,/^\<nobody\>./{print $0}‘ /etc/passwd
awk -F: ‘/^\<root\>/,/^\<nobody\>/{print $0}‘ /etc/passwd
awk -F: ‘(NR>=10&&NR<=20){print NR,$1}‘ /etc/passwd
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
awk -F : ‘BEGIN {print "USER USERID"} {print $1":"$3} END{print "end file"}‘ /etc/passwd
awk -F : ‘{print "USER USERID“;print $1":"$3} END{print "end file"}‘ /etc/passwd
awk -F: ‘BEGIN{print " USER UID \n--------------- "}{print $1,$3}‘ /etc/passwd
awk -F: ‘BEGIN{print " USER UID \n--------------- "}{print $1,$3}‘END{print "=============="} /etc/passwd
seq 10 |awk ‘i=0’ 不显示所有行
seq 10 |awk ‘i=1’ 显示所有行
seq 10 | awk ‘i=!i‘ 显示基数行
seq 10 |awk -v i=1 ‘!(i=!i)‘ 显示基数行
seq 10 | awk ‘{i=!i;print i}‘每执行一行,显示一次i的真假值
seq 10 | awk ‘!(i=!i)’ 显示偶数行
seq 10 |awk -v i=1 ‘i=!i‘ 显示偶数行
语法:if(condition){statement1}[else{statement2}]
If(condition1){statement}else if(condition2){statement2}else{statement3}
这种语法看着跟shell中的if--else语句相差无几,第一种格式是单if语句,执行机制是先判断条件(condition)部分,值为则true执行statement1部分语句,值为false则执行statement2部分的语句;第二种是多if语句,有多个条件多个语句,先判断第一个条件(condition1),值为true执行statement1部分的语句,值为false就判断下一个条件condition2,值为true就执行statement2,值为false就执行else后面的statement3语句;
使用场景:对awk取得的整行或某个字段做条件判断
示例:
awk -F: ‘{if($3>=1000)print $1,$3}‘ /etc/passwd
awk -F: ‘{if($NF=="/bin/bash") print $1}‘ /etc/passwd
awk ‘{if(NF\>5) print $0}‘ /etc/fstab
awk -F: ‘{if($3\>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}‘ /etc/passwd
awk -F: ‘{if($3\>=1000) printf "Common user: %s\n",$1; else printf "root or Sysuser: %s\n",$1}‘ /etc/passwd
df -h|awk -F% ‘/^\/dev/{print $1}‘|awk ‘$NF\>=80{print $1,$5}‘
awk ‘BEGIN{ test=100;if(test\>90){print "very good"} else if(test\>60){ print "good"}else{print "no pass"}}‘
语法:while(condition){statement;...}
执行机制:先判断再执行,条件真,进入循环;条件假退出循环,statement部分可以有多个语句,组合语句,在statement处应该有一条是条件判断的值发生变化的语句,否则容易进入死循环
使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用
示例:
awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}‘ /etc/grub2.cfg
awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=10) {print $i,length($i)}; i++}}‘ /etc/grub2.cfg
语法:do{statement;}while(condition)
执行机制:先执行再判断,先执行一遍statement,再判断condition,如果条件为真则进入下一轮循环,如果为假就退出,无论真假,至少执行一次循环体
示例:
awk ‘BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}‘
思考:下面两语句有何不同?
awk ‘BEGIN{i=0;print ++i,i}’
awk ‘BEGIN{i=0;print i++,i}’
前者输出的++i是先给i加1在输出,后者是先输出i再给i加值
语法:for (expr1;expr2;expr3){statement;...}
常见用法:for(var assignment;condition;iteration process){for-body}
执行机制:variable assignment(变量的初始值),condition(条件),iteration process(步长,也就是没执行一次循环体后,使变量的值发生变化的语句);for-body(循环体),先赋初值变量(variable),再判断变量的值是否符合条件(condition),符合就执行循环体部分(for-body),然后再给变量加上步长(iteration process),再判断条件,为真时执行循环体部分,为假退出循环......
特殊用法:for(var in array) {for-body}
执行机制:给var多个值,一次使用一个值,执行一次循环,有多少个值就执行多少次循环,直到把array的所有的值都用完,array代表一个数组。
示例:
awk ‘/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}‘ /etc/grub2.cfg
性能比较就是,看某个命令从执行到出结果时的时长,哪个时间最短就说明哪个命令性能更好,这个查看性能的命令就是time,在命令的前面写入time,把要执行的命令用小括号括起来,再执行此命令,就会在显示执行结果的后面显示出时间
例:
time(awk‘BEGIN{ total=0;for(i=0;i<=10000;i++){total+=i;};print total;}‘)
time(total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
time(for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
time(seq –s ”+” 10000|bc)
语法:switch(expression) {case VALUE1 or /REGEXP1/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
执行机制:这个就相当于shell中的case语句,espression是一个表达式,当VALUE1的值满足REGEXP1的时候执行statement1,当VALUE2的值满足REGEXP2的时候,执行statement2语句,...当前面的所有条件都不满足的时候,执行default后面的statement n语句。
这两个语句的用法continue是提前结束当前这一轮循环,进入下一循环,break是结束当前的循环语句用于在for,while语句中
示例:
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++) {if(i%2==0)continue;sum+=i}print sum}‘
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++) {if(i==66)break;sum+=i}print sum}
由于awk是逐行进行处理的,一行一行的处理,直到所有的行都被处理完结束,也相当于一个循环,next语句就相当于for、while循环语句的continue语句,用来结束对本行的处理而直接进入下一行处理。
示例:
awk -F: ‘{if($3%2!=0) next; print $1,$3}‘ /etc/passwd
关联数组array[index-expression]
Index-expression(下标):
1)下标可以使用任意字符串;字符串要使用双引号括起来,例:weekdays[“mon”]="Monday“
2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串
3)若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
4)若要遍历数组中的每个元素,需使用for循环
5)格式:for(var in array) {for-body} var会遍历array的每个索引
示例:
awk ‘BEGIN{weekdays["mon"]="Monday";weekdays["tue"] ="Tuesday";for(i in weekdays) {print weekdays[i]}}‘
netstat -tan | awk ‘/^tcp/{state[$NF]++}END {for(i in state) { print i,state[i]}}‘
awk ‘{ip[$1]++}END{for(i in ip) {print i,ip[i]}}‘ /var/log/httpd/access_log
例图:
使用awk查看一个文件中的每一行的重复次数
函数分为系统函数和自定义函数,
数值处理:
rand():返回0和1之间一个随机数;使用这个函数之前必须先写一个srand()语句,才能产生随机0到1之间的小数,保留6位,如下图:
示例:产生10个0到100的随机整数
字符串处理:
length([s]):返回指定字符串的长度,并且在这种模式下,不管是字母数字还是汉字,都是一个占用一个字符
sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹 配的内容替换为s
gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换 为s所表示的内容
split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存 至array所表示的数组中,第一个索引值为1,第二个索引值为2,…
例图:
格式:
function name ( parameter, parameter, ... ) {
statements
return expression
}
执行机制:把函数编辑在一个文件中,name是函数的名字,parameter是虚参,调用函数的括号内的实参,每一个实参对应着一个虚参,在函数中虚参是调用实参的值来执行statement部分的表达式,return的作用类似shell中的echo,是打印结果在终端上,expression可以是变量名或者是表达式,
示例:编辑文件abc,写一个函数,要求取最大值,
格式:system(“cmd”)
标签:文本三剑客awk awk循环 awk控制语句 awk数组 awk函数
原文地址:http://blog.51cto.com/13570214/2094293