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的操作
[root@centosliuhua ~]# awk ‘{print "hello,awk"}‘ /etc/fstab
[root@centosliuhua ~]# 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
[root@centosliuhua ~]# awk -F: ‘{print $1, $3}‘ /etc/passwd
[root@centosliuhua ~]# awk BEGIN‘{print "hellow,word"}‘
[root@centosliuhua ~]# awk ‘END{print "hellow,word"}‘ /etc/fstab END需要有文件。
hellow,word
(二)awk的内置变量
FS:输入字段分隔符,默认为空白字符
[root@centosliuhua ~]# awk -v FS=‘:‘ ‘{print $1,$3}‘ /etc/passwd 只指定输入字段分隔符为‘:’
awk -v FS=‘:‘ ‘{print $1,FS,$3}‘ /etc/passwd 指定输入输出分隔符都为“:”
[root@centosliuhua ~]# awk -F: ‘{print $1,$3}‘ /etc/passwd 不指定输出分隔符时为默认输出空白分割符。
OFS:输出字段分隔符,默认为空白字符
[root@centosliuhua ~]# awk -v FS=‘:‘ -v OFS=‘@‘ ‘{print $1,$3}‘ /etc/passwd 指定了输入和输出分割符。
root@0
bin@1
daemon@2
adm@3
[root@centosliuhua ~]# awk -F: -v OFS=‘@‘ ‘{print $1,$3}‘ /etc/passwd 此用法同上一条。
RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效 默认记录分隔符时回车。
[root@centosliuhua app]# cat /app/asd
11.222:444:555:
6666:2543:9527:
3333:1:3
[root@centosliuhua app]# awk -v RS=: ‘{print }‘ /app/asd
11.222
444
555
6666
2543
9527
3333
1
3
ORS:输出记录分隔符,输出时用指定的符号代替换行符。
@[root@centosliuhua app]# cat /app/asd
a 11.222:444:555:
b 66 66:25.43:9527:
3333:1:3
[root@centosliuhua app]# awk -v RS=: -v FS=. -v ORS="@" ‘{print $1}‘ /app/asd
a 11@444@555@
b 66 66@25@9527@
3333@1@3
解释:输入分隔符为“:”,然后以“.”为记录分隔符 ,最后以@为输出分隔符输出第一列。
NF:字段数量
[root@centosliuhua app]# awk -F: ‘{print NF}‘ /etc/passwd
7
7
7
7
7
[root@centosliuhua app]# awk -F: ‘{print $(NF-1)}‘ /etc/passwd 引用内置变量不用$
显示每一个记录中有多少个字段,并将其统计结果输出。
NR:行号
[root@centosliuhua app]# awk ‘{print NR}‘ /etc/passwd 打印行号
[root@centosliuhua app]# awk ‘END{print NR}‘ /etc/passwd 打印总行数。
FNR:各文件分别计数,行号
[root@centosliuhua app]# awk ‘{print FNR}‘ /etc/passwd /etc/fstab
FILENAME:当前文件名:
[root@centosliuhua app]# awk ‘{print FILENAME}‘ /etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
ARGC:命令行参数的个数
[root@centosliuhua app]# awk ‘BEGIN{print ARGC}‘ a b c d 其中awk也算一个命令参数。
5
ARGV:数组,保存的是命令行所给定的各参数
[root@centosliuhua app]# awk ‘BEGIN{print ARGV[1]}‘ a b c d
a
[root@centosliuhua app]# awk ‘BEGIN{print ARGV[2]}‘ a b c d
b
[root@centosliuhua app]# awk ‘BEGIN{print ARGV[0]}‘ a b c d
awk
(三)awk中自定义变量
(1)-v var=value
(2) 在program 中直接定义
[root@centosliuhua app]# awk -v test="hello ,word" ‘BEGIN{print test}‘
hello ,word
[root@centosliuhua app]# awk ‘BEGIN{test="hello word";print test}‘
hello word
[root@centosliuhua app]# awk -F: ‘{sex="male";print $1,sex,age;age=18}‘ /etc/passwd
root male
bin male 18
daemon male 18
可以看出变量的位置不懂是会影响输出结果的。
也可以写在文件里:
[root@centosliuhua app]# cat asd
{age=18;sex="male";print $1,sex,age}
[root@centosliuhua 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
[root@centosliuhua app]# awk -F: ‘{printf "%-20s %10d\n",$1,$3}‘ /etc/passwd
root 0
bin 1
daemon 2
[root@centosliuhua 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
[root@centosliuhua 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:转换为数值
字符串操作符:
= ,+= ,-= ,*= ,/= , %= ,^= ,++ , --
比较操作符:
== ,!= ,> ,>= ,< , <=
模式匹配符:~ :左边是否和右边匹配包含 !~ :是否不匹配
[root@centosliuhua app]# awk -F: ‘$0 ~ "^root" {print $1}‘ /etc/passwd
root
[root@centosliuhua 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
[root@localhost ~]# seq 10 |awk ‘{if($1%2==0){print $1}}‘
2
4
6
8
10
逻辑操作符:
与&& , 或|| , 非!
三目表达式:
x>y?x=y:y=x
[root@localhost ~]# awk -F: ‘$3>1000 && $3<=3000 {print $1,$3}‘ /etc/passwd
liubei 1001
[root@localhost ~]# awk -F: ‘$3>3000 || $3<=5 {print $1,$3}‘ /etc/passwd
[root@localhost ~]# awk -F: ‘!($3>10) {print $1,$3}‘ /etc/passwd
[root@localhost ~]# 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
[root@localhost ~]# awk ‘/^[[:blank:]]*UUID/ {print $1}‘ /etc/fstab
(3)relational expression :关系表达式,结果为真才会被处理
真:结果为非零值,非空字符串
假:结果为空字符串或0值
[root@localhost ~]# seq 10 |awk ‘0‘ [root@localhost ~]# seq 10 |awk ‘1‘ 1 2 [root@localhost ~]# seq 10 |awk ‘i=!i‘ 1 3 5 7 9 [root@localhost ~]# seq 10 |awk ‘!(i=!i)‘ 2 4 6 8 10
(4)line ranges:行范围
格式: awk ‘/pat1/,/pat2/{}‘ file 此格式不知持直接给出数字格式
[root@localhost ~]# awk -F: ‘/^sync/,/^o/{print $1}‘ /etc/passwd
sync
shutdown
halt
mail
operator
[root@localhost ~]# awk -F: ‘(NR>=10 && NR<=20){print NR,$1}‘ /etc/passwd
(5)BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
[root@localhost ~]# 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取得的整行或某个字段做条件判断
[root@localhost ~]# df -h |awk -F% ‘/^\/dev\/sd[[:lower:]][[:digit:]]\>/{print $1}‘|awk ‘$NF>50{printf "%-10s %s\n",$1,$5}‘
[root@localhost ~]# 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;...}
条件为真时进入循环,条件为假时退出循环
使用场景:
对一行内的多个字段逐一类似处理使用
对数组中的各元素逐一处理时使用
[root@localhost app]# awk ‘/^[[:space:]]+linux16/{n=1;while(n<NF){print $n,length($n);n++}}‘ /app/grub2.cfg
do-while循环
语法:do{statement;...}while(condition)
意义:无论真假,至少执行一次循环体
[root@localhost app]# awk ‘BEGIN{sum=0;i=1;do{sum+=i;i++}while(i<=100);print sum}‘
[root@localhost 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}
[root@localhost app]# awk ‘/^[[:space:]]+linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}‘ /app/grub2.cfg
[root@localhost app]# time seq -s "+" 1000000|bc
500000500000
real 0m0.421s
user 0m0.212s
sys 0m0.252s
[root@localhost app]# time awk ‘BEGIN{for(i=1;i<=1000000;i++){sum+=i}{print sum}}‘
500000500000
real 0m0.094s
user 0m0.092s
sys 0m0.002s
[root@localhost 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:提前结束对本行的处理而直接进入下一行处理。
[root@localhost app]# awk -F: ‘{if($3%2!=1){next};print $1,$3}‘ /etc/passwd 打印奇数行。
(七)awk数组
关联数组:array[index-expression]
(1)可使用任意字符串,字符串要使用双引号括起来
(2)如果某数组元素实现不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
[root@localhost app]# awk ‘BEGIN{weekday["mon"]="monday";weekday["tue"]="tuesday";weekday["thr"]="thrsday";for (n in weekday){print n,weekday[n]}}‘
[root@centosliuhua ~]# awk ‘{ip[$1]++}END{for(n in ip){print n, ip[n]}}‘ /root/access_log 统计日志中每一个IP访问的次数
[root@centosliuhua ~]# netstat -tan |awk ‘/^tcp/{state[$NF]++}END{for(n in state){print n,state[n]}}‘
ESTABLISHED 1
LISTEN 11
[root@centosliuhua ~]# awk -F: ‘!shuzu[$0]++‘ /etc/passwd 利用awk函数实现去除重复项
(八)awk 函数
数值处理:
rand():返回0和1之间一个随机数:可以用它来显示一个十,一百等以内的随机整数
[root@centosliuhua ~]# awk ‘BEGIN{srand();for (n=0;n<1;n++){print int(rand()*100)}}‘
length([s]):返回指定字符串的长度
gsub(r,s,[t]):对字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容。
[root@centosliuhua ~]# echo "2018:3:31/15:34:31" |awk -F/ ‘gsub(":","-",$1)‘
2018-3-31 15:34:31
[root@centosliuhua ~]# echo "2018:3:31/15:34:31" |awk ‘gsub(":","-",$1)‘
2018-3-31/15-34-31
split(s,arry,[r]):以r为分隔符,切割字符串s,并将切割的结果保存至arry所表示的数组中第一个索引值为一,第二个索引值为2,......
[root@centosliuhua ~]# 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
}
[root@centosliuhua lianxi321]# awk -v a=200 -v b=30 -f funct_1.awk
200
[root@centosliuhua 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)}
[root@centosliuhua lianxi321]# cat test.awk
#!/bin/awk -f
{ print $1,$3 }
[root@centosliuhua lianxi321]# ./test.awk -F: /etc/passwd