gawk - pattern scanning and processing language
awk是指向gawk命令的链接,它的工作模式是对文本逐行进行处理,将每一行按照输入时分隔符切片,每一个切片内容用awk内建的位置变量来存放,然后可以对每一片内容进行输出、循环等操作,不指定输入分隔符时默认分隔符为空白。
awk基本用法:awk [options] 'program' FILE...
program: PATTERN{ACTION STATEMENTS},语句之间用分号分隔
示例:
[root@localhost scripts]# awk '/^UUID/{print $2,$4}' /etc/fstab
/boot defaults
swap defaults
选项options:
-F:指明输入时用到的字段分隔符
-v var=VALUE:自定义变量
1.指明输入时字段分隔符为:,打印第1个切片内容,比如对/etc/passwd处理
[root@localhost scripts]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
2.使用内建变量FS指明输入时的分隔符为冒号,打印第一个片段内容
[root@localhost scripts]# awk -v FS=':' '{print $1}' /etc/passwd
root
bin
1.print使用相关要点
用法:print item1,item2,...
要点:
1.itm之间用逗号分隔
2.输出的各item可以是字符串,也可以是数值
3.如果省略item,默认print是:print $0,打印整行内容
1.print后面不跟item时,是将整行内容输出,也即是print $0
[root@localhost scripts]# awk -F: '{print}' /etc/passwd root:x:0:0:root:/root:/bin/bash
2.变量
2.1内建变量
FS:input field seperator,输入时的分隔符,默认为空白字符
OFS:output field seperator,输出时的分隔符,默认为空白字符
RS:input record seperator,输入时的换行符
ORS:output record seperator,输出时的换行符
NF:number of field,字段数量
NR:number of record,行数
FNR:各文件分别计数:行数
FILENAME:当前文件名
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行所给定的各参数
内建变量相关示例
1.FS
[root@localhost scripts]# awk -v FS=':' '{print $1}' /etc/passwd
root
bin
2.OFS
[root@localhost scripts]# awk -v FS=':' -v OFS='@@' '{print $2,$3,$7}' /etc/passwd
x@@0@@/bin/bash
x@@1@@/sbin/nologin
3.RS
[root@localhost scripts]# awk -v RS='o' '{print $1,$3}' /etc/passwd
4.ORS
[root@localhost scripts]# awk -v ORS='##' '{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash##bin:x:1:1:bin:/bin:/sbin/nologin##
5.NF
显示每行多少段
[root@localhost scripts]# awk -v FS=: '{print NF}' /etc/passwd
7
显示字后一段的值
[root@localhost scripts]# awk -v FS=: '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
6.NR
[root@localhost scripts]# awk '{print NR}' /etc/passwd
1
2
7.FNR
[root@localhost scripts]# awk '{print FNR}' /etc/fstab /etc/passwd
1
2
3
4
5
1
2
3
8.FILENAME
[root@localhost scripts]# awk '{print FILENAME}' /etc/fstab
/etc/fstab
9.ARGC
[root@localhost scripts]# awk '{print ARGC}' /etc/fstab
2
10.ARGV
[root@localhost scripts]# awk '{print ARGV[1]}' /etc/fstab /etc/fstab
tips: ARGV[0]: awk ARGV[1]:/etc/fstab
2.2自定义变量
1. -v var=value
[root@localhost scripts]# awk -v test='hello awk' 'BEGIN{print test}'
hello awk
[root@localhost scripts]# awk -v test='hello awk' '{print test}' /etc/fstab 此时跟上文件名的作用是显示多少行
hello awk
hello awk
2. 在program中直接定义
[root@localhost scripts]# awk '{test="hello awk";print test}' /etc/fstab
hello awk
hello awk
3.printf命令 格式化输出:printf FORMAT,item1,item2,... 格式符 %c:显示字符的ASCII码 %d,%i:显示十进制整数 %e,%E:科学计数法数值显示 %f:显示为浮点数 %g,%G:以科学计数法或浮点形式显示数值 %s:显示字符串
%u:无符号整数
%%:显示%自身
修饰符
#[.#]:第一个数字控制显示的宽度,第二个#表示小数点后的精度,比如%3.1f
默认是右对齐,-:左对齐
+:显示数值的符号
相关示例
[root@localhost scripts]# awk -F: '{printf "ckh%s
",$7}' /etc/passwd
ckh/bin/bash
ckh/sbin/nologin
[root@localhost scripts]# awk -F: '{printf "Username:%-15s,UID:%d
",$1,$3}' /etc/passwd
Username:root ,UID:0
Username:bin ,UID:1
Username:daemon ,UID:2
4.操作符
算术操作符
x+y,x-y,x*y,x/y,x^y,x%y
赋值操作符
=,+=,*=,/=,%=,^=
++,--
比较操作符:
>,>=,<,<=,!=,==
模式匹配符
~:是否匹配
!~:是否不匹配
逻辑操作符
&&
||
!
函数调用
function_name(arg1,arg2,...)
条件表达式:
selector?if-true-expression:if-false-expression
条件表达式示例
[root@localhost scripts]# awk -v FS=':' '{$3>=500?usertype="common user":usertype="Sysadmin or Sysuser";printf "%15s:%s ",$1,usertype}' /etc/passwd root:Sysadmin or Sysuser bin:Sysadmin or Sysuser
5.PATTERN
1. empty:空模式,匹配每一行
2. /regular expression/:仅处理能够被此处的模式匹配到的行
[root@localhost scripts]# awk '!/^UUID/{print $1}' /etc/fstab //以UUID为开头的行之外的行
#
#
3. relational expression:关系表达式,结果有真有假;结果为真才会被处理
真:结果为非0值,非空字符串
[root@localhost scripts]# awk -F: '$NF=="/bin/bash"{print $1,$7}' /etc/passwd //最后一段是/bin/bash的字段
root /bin/bash
chengkaihua /bin/bash
[root@localhost scripts]# awk -F: '$NF~/bash$/{print $1,$7}' /etc/passwd //以模式匹配bash结尾的片段
root /bin/bash
chengkaihua /bin/bash
4.line ranges:行范围
startline,endline:/pat1/,/pat2/
注意:不支持直接给出数字的格式
[root@localhost scripts]# awk -F: '(NR>=2&&NR<=5){print $1}' /etc/passwd
bin
daemon
5.BEGIN/END模式
BEGIN{}:仅在开始处理文本之前执行一次
END{}:仅在文本处理完成之后执行一次
[root@localhost scripts]# awk -F: 'BEGIN{print " USERNAME UID
-------------------------------"}{printf "%15s,%10d", $1,$3}END{print "====================
end"}' /etc/passwd
6.常用的action
1.EXPRESSIONS
2.Control statements:if,while等
3.Compound statements:组合语句
4.input statements
5.output statements
7.控制语句
if(condition){statements}
if(condition){statements}else{statements}
while(condition){statements}
do{statements}while(condition)
for(expr1;expr2;expr3){statements}
break
continue
delete aray[index]
delete array
exit
{ statements }
7.1 if-else
语法:if(condition)statement[else statement]
使用场景: 对awk取得的整行或某个字段做条件判断;
示例:
id号大于500为普通用户,其他为系统用户
[root@localhost scripts]# awk -F: '{if($3>=500){printf "Common User:%s ",$1}else{printf "Sysadmin or Sysuser:%s ",$1}}' /etc/passwd Sysadmin or Sysuser:root Sysadmin or Sysuser:bin
以/bin/bash结尾的字段
[root@localhost scripts]# awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd
root
chengkaihua
每行字段大于5个,则显示整行
[root@localhost scripts]# awk '{if(NF>5)print $0}' /etc/fstab
df命令中use大于百分之20的设备
# df -h | awk -F% '/^/dev/{print $1}' | awk '{if($NF>20)print $1}'
7.2 while循环
语法:while(condition)statement
条件为"真",进入循环,条件为"假",退出循环
使用场景: 对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用
示例:
# awk '/^[[:space:]]*/{i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/grub2.cfg
# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7){print $i,length($i)}; i++}}' /etc/grub2.cfg
7.3 do-while循环
语法:do statement while(condition)
意义:至少执行一次循环体
7.4 for循环
语法:for(expr1;expr2;epr3) statement
for(variable assignment;iteration process) {for-body}
特殊用法:
能够遍历数组中的元素
语法:for(var in array){for-body}
# awk '/^[[:space:]]*linux16/{for(i=1;i<NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
7.5 switch语句 语法: switch(expression){case VALUE1 or /REGEXP/;statement... default:statement}
7.6 break和continue break [n] continue
7.7 next 提前结束对本行的处理而直接进入下一行
示例:
显示偶数行 [root@localhost scripts]# awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd root 0 daemon 2 lp 4
8.array 关联数组:array[index-expression]
index-expression:
1.可使用任意字符串
2.如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为"空串"
若要判断数组中是否存在某元素,要使用"index in array"格式进行
给数组赋值:
weekdays[mon]="Monday"
给数组赋值并打印第一个值
[root@localhost scripts]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
Monday
若要遍历数组中的每个元素,要使用for循环 for(var in array){for-body} [root@localhost scripts]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays){print weekdays[i]}}' Monday Tuesday
统计netstat -atn命令结果中各状态结果的出现次数 [root@localhost scripts]# netstat -atn | awk '/^tcp>/{state[$NF]++}END{for(i in state){print i,state[i]}}' ESTABLISHED 2 LISTEN 8
[root@localhost tmp]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /tmp/access.log 192.168.0.11 3 192.168.0.12 6
统计/etc/fstab文件中各文件系统类型出现的次数 [root@localhost ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab swap 1 ext4 1
统计指定文件中每个单词出现的次数 [root@localhost ~]# awk '{for(i=1;i<NF;i++){word[$i]++}}END{for(i in word){print i,word[i]}}' /etc/fstab mount(8) 1 Accessible 1 pages 1 reference, 1
9.函数 9.1 内置函数 rand():返回0和1之间一个随机数 [root@localhost ~]# awk 'BEGIN{print rand()}' 0.237788
字符串处理
length([s]):返回指定字符串的长度
sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容.也就是将t中的内容r替换为s
# awk -F: '{print sub(o,O,$1)}' /etc/passwd
gsub(r,s,[t]):全局替换
split(s,a[],r):以r为分隔符切割字符串s,并将切割后的结果保存至a所表示的数组中
注意:awk中的数组从1开始编号
netstat -atn命令中客户端连接的ip出现次数,采用split分隔符
[root@localhost ~]# netstat -atn | awk '/^tcp>/{split($5,ip,":");count[ip[1]]++;}END{for(i in count){print i,count[i]}}' 192.168.0.100 3 0.0.0.0 4
9.2 自定义函数