awk总结
(一)awk模式扫描和处理语言
基本用法:
awk [options] ‘program‘ var=value file...
awk [options] -f programfile var=value file...
awk [options] ‘BEGIN{action;....} pattern{action;...} END{action;....}‘ file...
program:通常是被双引号或单引号引起的
选项:
-F :知名输入时用到的字符分割段。
-v var=value : 自定义变量
program:pattern{action statements;...}
patten和action:
pattern 决定动作语句何时触发及触发事件,包括BEGIN ,END语句
action statements:对数据进行处理,放在{}内指明print,printf
分隔符,域和记录:
awk执行时,由分隔符分割的字段称为域标记$1,$2..$n称为标示域。其中$0为所有域,注意此种$和shell中含义不同
所读取的文件的每一行称为记录
如果省略action,则默认执行print $0的操作
[[email protected] ~]# awk ‘{print "hello,awk"}‘ /etc/fstab [[email protected] ~]# awk ‘{print }‘ /etc/fstab
awk的工作原理:
(1)执行BEGIN{action...}语句块中的语句
(2)从文件或者标准输入读取一行,然后执行pattern{action;...}语句块,它逐行扫描文件,从第一行到最后一行指导文件被读取完毕。
(3)当渎至输入流末尾时执行END{action;...}语句块
print的格式:print #,#,#.....
(1)多个#用逗号分隔
(2)输出可以是字符串也可以是数值。
(3)如果省略相当于print $0
注意: (1)BEGIN语句在awk开始从输入流中读取行之前被执行,是一个可选语句块,比如变量初始化,打印出表格的表头等语句通常可以写在BEGIN语句块中。
(2)END是在输入完之后被读取执行的,所以可以把结果写在其语句块中。
(3)pattern 语句块中通用的命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print},即打印每一个读取到的行
awk -F: ‘{print $1}‘ /etc/passwd [[email protected] ~]# awk -F: ‘{print $1, $3}‘ /etc/passwd [[email protected] ~]# awk BEGIN‘{print "hellow,word"}‘ [[email protected] ~]# awk ‘END{print "hellow,word"}‘ /etc/fstab END需要有文件。 hellow,word
(二)awk的内置变量
FS:输入字段分隔符,默认为空白字符
[[email protected] ~]# awk -v FS=‘:‘ ‘{print $1,$3}‘ /etc/passwd 只指定输入字段分隔符为‘:’ awk -v FS=‘:‘ ‘{print $1,FS,$3}‘ /etc/passwd 指定输入输出分隔符都为“:” [[email protected] ~]# awk -F: ‘{print $1,$3}‘ /etc/passwd 不指定输出分隔符时为默认输出空白分割符。
OFS:输出字段分隔符,默认为空白字符
[[email protected] ~]# awk -v FS=‘:‘ -v OFS=‘@‘ ‘{print $1,$3}‘ /etc/passwd 指定了输入和输出分割符。 [email protected] [email protected] [email protected] [email protected] [[email protected] ~]# awk -F: -v OFS=‘@‘ ‘{print $1,$3}‘ /etc/passwd 此用法同上一条。
RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效 默认记录分隔符时回车。
[[email protected] app]# cat /app/asd 11.222:444:555: 6666:2543:9527: 3333:1:3 [[email protected] app]# awk -v RS=: ‘{print }‘ /app/asd 11.222 444 555 6666 2543 9527 3333 1 3
ORS:输出记录分隔符,输出时用指定的符号代替换行符。
@[[email protected] app]# cat /app/asd a 11.222:444:555: b 66 66:25.43:9527: 3333:1:3 [[email protected] app]# awk -v RS=: -v FS=. -v ORS="@" ‘{print $1}‘ /app/asd a [email protected]@[email protected] b 66 [email protected]@[email protected] [email protected]@3 解释:输入分隔符为“:”,然后以“.”为记录分隔符 ,最后以@为输出分隔符输出第一列。
NF:字段数量
[[email protected] app]# awk -F: ‘{print NF}‘ /etc/passwd 7 7 7 7 7 [[email protected] app]# awk -F: ‘{print $(NF-1)}‘ /etc/passwd 引用内置变量不用$
显示每一个记录中有多少个字段,并将其统计结果输出。
NR:行号
[[email protected] app]# awk ‘{print NR}‘ /etc/passwd 打印行号 [[email protected] app]# awk ‘END{print NR}‘ /etc/passwd 打印总行数。
FNR:各文件分别计数,行号
[[email protected] app]# awk ‘{print FNR}‘ /etc/passwd /etc/fstab
FILENAME:当前文件名:
[[email protected] app]# awk ‘{print FILENAME}‘ /etc/fstab /etc/fstab /etc/fstab /etc/fstab
ARGC:命令行参数的个数
[[email protected] app]# awk ‘BEGIN{print ARGC}‘ a b c d 其中awk也算一个命令参数。 5
ARGV:数组,保存的是命令行所给定的各参数
[[email protected] app]# awk ‘BEGIN{print ARGV[1]}‘ a b c d a [[email protected] app]# awk ‘BEGIN{print ARGV[2]}‘ a b c d b [[email protected] app]# awk ‘BEGIN{print ARGV[0]}‘ a b c d awk
(三)awk中自定义变量
(1)-v var=value
(2) 在program 中直接定义
[[email protected] app]# awk -v test="hello ,word" ‘BEGIN{print test}‘ hello ,word [[email protected] app]# awk ‘BEGIN{test="hello word";print test}‘ hello word [[email protected] app]# awk -F: ‘{sex="male";print $1,sex,age;age=18}‘ /etc/passwd root male bin male 18 daemon male 18 可以看出变量的位置不懂是会影响输出结果的。 也可以写在文件里: [[email protected] app]# cat asd {age=18;sex="male";print $1,sex,age} [[email protected] app]# awk -F: -f asd /etc/passwd root male 18 bin male 18 daemon male 18
(四)printf 格式化输出:
(1)必须制定FORMAT
(2)不会自动换行,需要给出换行符,\n
(3)FORMAT中需要分别为后面的每一个item制定格式符
格式符:
%c :显示字符的ASCII码
%d %i:显示十进制整数
%e %E :显示科学计数法数值
%f :显示浮点数
%g %G :以科学计数法或浮点形式显示数值
%s :显示字符串
%u :无符号整数
%% :显示%自身
修饰符:
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度,%3.1f
- : 左对齐(默认为右对齐) %-20s
+ : 显示数值的正负符号%+d
[[email protected] app]# awk -F: ‘{printf "%-20s %10d\n",$1,$3}‘ /etc/passwd root 0 bin 1 daemon 2 [[email protected] app]# awk -F: ‘{printf "username:%-20s UID:%10d\n",$1,$3}‘ /etc/passwd username:root UID: 0 username:bin UID: 1 username:daemon UID: 2 [[email protected] app]# awk -F: ‘{printf "username:%-20s UID:%-10d\n",$1,$3}‘ /etc/passwd username:root UID:0 username:bin UID:1 username:daemon UID:2
(五)操作符:
算术操作符:
x+y,x-y,x*y,x/y,x^y,x%y
-x:转换为负数
+x:转换为数值
字符串操作符:
= ,+= ,-= ,*= ,/= , %= ,^= ,++ , --
比较操作符:
== ,!= ,> ,>= ,< , <=
模式匹配符:~ :左边是否和右边匹配包含 !~ :是否不匹配
[[email protected] app]# awk -F: ‘$0 ~ "^root" {print $1}‘ /etc/passwd root [[email protected] app]# awk ‘$0 !~ /root/‘ /etc/passwd bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin [[email protected] ~]# seq 10 |awk ‘{if($1%2==0){print $1}}‘ 2 4 6 8 10
逻辑操作符:
与&& , 或|| , 非!
三目表达式:
x>y?x=y:y=x
[[email protected] ~]# awk -F: ‘$3>1000 && $3<=3000 {print $1,$3}‘ /etc/passwd liubei 1001 [[email protected] ~]# awk -F: ‘$3>3000 || $3<=5 {print $1,$3}‘ /etc/passwd [[email protected] ~]# awk -F: ‘!($3>10) {print $1,$3}‘ /etc/passwd [[email protected] ~]# awk -F: ‘$3<1000?usertype="systemuser":usertype="common user"{printf "user:%-20s %s %s\n" ,$1, "is", usertype}‘ /etc/passwd
PATTERN:根据pattern条件,过滤匹配的行,再做处理
(1)如果未指定,控模式则会匹配每一行
(2)/regular expression/:仅处理能够被模式匹配到的行,需要用/ / 括起来
~#]awk‘/^UUID/{print $1}’/etc/fstab [[email protected] ~]# awk ‘/^[[:blank:]]*UUID/ {print $1}‘ /etc/fstab
(3)relational expression :关系表达式,结果为真才会被处理
真:结果为非零值,非空字符串
假:结果为空字符串或0值
[[email protected] ~]# seq 10 |awk ‘0‘ [[email protected] ~]# seq 10 |awk ‘1‘ 1 2 [[email protected] ~]# seq 10 |awk ‘i=!i‘ 1 3 5 7 9 [[email protected] ~]# seq 10 |awk ‘!(i=!i)‘ 2 4 6 8 10
(4)line ranges:行范围
格式: awk ‘/pat1/,/pat2/{}‘ file 此格式不知持直接给出数字格式
[[email protected] ~]# awk -F: ‘/^sync/,/^o/{print $1}‘ /etc/passwd sync shutdown halt mail operator [[email protected] ~]# awk -F: ‘(NR>=10 && NR<=20){print NR,$1}‘ /etc/passwd
(5)BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
[[email protected] ~]# awk -F: ‘BEGIN{print "username salar\n--------------------------------"}{printf "%-20s %-10s\n" ,$1,$3}{sum+=$3}END{print "pingjungongzi:" sum/NR}‘ /etc/passwd
(六)action的常用分类
(1)算数比较表达式
(2)if while 等循环语句
(3)组合语句
(4)输入
(5)输出
awk中的控制语句if-else
语法:if(控制条件){statement;...}[else statement]
if(condition1){statement;...}if(condition2){statement;...}else{statement;...}
使用场景:对awk取得的整行或某个字段做条件判断
[[email protected] ~]# df -h |awk -F% ‘/^\/dev\/sd[[:lower:]][[:digit:]]\>/{print $1}‘|awk ‘$NF>50{printf "%-10s %s\n",$1,$5}‘ [[email protected] ~]# awk -F: ‘{if($3<1000){level="low"}else if($3<3000 && $3>1000){level="Soso"}else{level="High"};printf "%-20s%-10s%s\n",$1,$3,level }‘ /etc/passwd
awk中的控制语句while循环:
语法:while(condition){statement;...}
条件为真时进入循环,条件为假时退出循环
使用场景:
对一行内的多个字段逐一类似处理使用
对数组中的各元素逐一处理时使用
[[email protected] app]# awk ‘/^[[:space:]]+linux16/{n=1;while(n<NF){print $n,length($n);n++}}‘ /app/grub2.cfg
do-while循环
语法:do{statement;...}while(condition)
意义:无论真假,至少执行一次循环体
[[email protected] app]# awk ‘BEGIN{sum=0;i=1;do{sum+=i;i++}while(i<=100);print sum}‘ [[email protected] app]# echo {1..10} |awk ‘{i=1;while(i<=NF){if($i%2==0){print $i, "is oushu"}else{print $i, "is jishu"};i++}}‘
for循环:
语法:for(expr1;expr2;expr3){statement;...}
常见用法:
for(variable assignment;condition;iteration process)
{for-body}
特殊用法:能够遍历数组中的元素
语法:for(var in array){for-body}
[[email protected] app]# awk ‘/^[[:space:]]+linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}‘ /app/grub2.cfg [[email protected] app]# time seq -s "+" 1000000|bc 500000500000 real 0m0.421s user 0m0.212s sys 0m0.252s [[email protected] app]# time awk ‘BEGIN{for(i=1;i<=1000000;i++){sum+=i}{print sum}}‘ 500000500000 real 0m0.094s user 0m0.092s sys 0m0.002s [[email protected] app]# time ( sum=0; for (( i=0;i<=1000000;i++ ));do let sum+=i;done;echo $sum) 500000500000 real 0m6.469s user 0m6.203s sys 0m0.264s
switch语句:
语法:switch(expression){case VALUE1 or /REGEXP/:statement1;case VALUE2 or /REGEXP2/:statement2;...;default:statementn}
break和continue next
break:结束循环,continue:跳出本次循环 next:提前结束对本行的处理而直接进入下一行处理。
[[email protected] app]# awk -F: ‘{if($3%2!=1){next};print $1,$3}‘ /etc/passwd 打印奇数行。
(七)awk数组
关联数组:array[index-expression]
(1)可使用任意字符串,字符串要使用双引号括起来
(2)如果某数组元素实现不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
[[email protected] app]# awk ‘BEGIN{weekday["mon"]="monday";weekday["tue"]="tuesday";weekday["thr"]="thrsday";for (n in weekday){print n,weekday[n]}}‘ [[email protected] ~]# awk ‘{ip[$1]++}END{for(n in ip){print n, ip[n]}}‘ /root/access_log 统计日志中每一个IP访问的次数 [[email protected] ~]# netstat -tan |awk ‘/^tcp/{state[$NF]++}END{for(n in state){print n,state[n]}}‘ ESTABLISHED 1 LISTEN 11 [[email protected] ~]# awk -F: ‘!shuzu[$0]++‘ /etc/passwd 利用awk函数实现去除重复项
(八)awk 函数
数值处理:
rand():返回0和1之间一个随机数:可以用它来显示一个十,一百等以内的随机整数
[[email protected] ~]# awk ‘BEGIN{srand();for (n=0;n<1;n++){print int(rand()*100)}}‘
length([s]):返回指定字符串的长度
gsub(r,s,[t]):对字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容。
[[email protected] ~]# echo "2018:3:31/15:34:31" |awk -F/ ‘gsub(":","-",$1)‘ 2018-3-31 15:34:31 [[email protected] ~]# echo "2018:3:31/15:34:31" |awk ‘gsub(":","-",$1)‘ 2018-3-31/15-34-31
split(s,arry,[r]):以r为分隔符,切割字符串s,并将切割的结果保存至arry所表示的数组中第一个索引值为一,第二个索引值为2,......
[[email protected] ~]# netstat -tan |awk ‘/^tcp\>/{split($5,ips,":");count[ips[1]]++}END{for (n in count){print n,count[n]}}‘
自定义函数
格式:function name (parameter,....){
statements
return expression
}
[[email protected] lianxi321]# awk -v a=200 -v b=30 -f funct_1.awk 200 [[email protected] lianxi321]# cat funct_1.awk #!/bin/awk -f function max(v1,v2){ v1>v2?var=v1:var=v2 return var } BEGIN{print max(a,b)} [[email protected] lianxi321]# cat test.awk #!/bin/awk -f { print $1,$3 } [[email protected] lianxi321]# ./test.awk -F: /etc/passwd