AWK

mac2024-05-16  37

一.AWK基本概念

1.基本用法

1.Centos中的文本处理工具 1)grep,egrep,fgrep:基于pattern(模式)的文本过滤工具

2)sed:流编辑器,行编辑器;通过模式空间,保持空间实现编辑

3)AWK:报告生成器,实现格式化文本输出

gawk - pattern scanning and processing language:基于模式扫描以及语言处理 1.AWK: Aho, Weinberger, Kernighan --> New AWK, NAWK 2.现如今一般使用的是GNU awk,即为gawk awk实际为gawk的符号链接 [root@sakura ~]# which awk /usr/bin/awk [root@sakura ~]# ls -l /usr/bin/awk "lrwxrwxrwx. 1 root root 4 5月 6 16:16 /usr/bin/awk -> gawk" 12345678

ps:gwak是一种过程式编程语言。gwak还支持条件判断,数组,循环等各种编程语言中所有可以使用的功能,因此可以将其称为一种脚本语言解释器。 2.基本用法:gawk [options] 'program' FILE ... 1)program:pattern{action statements}

1.program:编程语言 2.pattern:模式 3.action statements:动作语句,可以由多个语句组成,各个语句间使用分号分隔;例如print;pringtf 123

2)-F选项:指明输入时用到的字段分隔符

3)-v var=value:自定义变量

4)awk在处理文本时也是一次读取一行,根据分隔符来进行切片,将分割出来的每一片都保存在awk的内部变量中,其分别为$1,$2,$3…以此类推至最后一个变量

3.print:print item1,item2,....;awk的输出命令之一 1)1)item:字符串,用引号引用,并且各item之间需要使用,隔开;例如print “kasumi”,“world”

[root@sakura ~]# awk -F: '{print $1,$3}' /etc/passwd root 0 bin 1 daemon 2 若各item间未使用,隔开,则会将$1$3连续输出 [root@sakura ~]# awk -F: '{print $1 $3}' /etc/passwd root0 bin1 [root@sakura ~]# awk -F: '{print $1$3}' /etc/passwd root0 bin1 ps:其输出时默认的分隔符为空白字符 12345678910111213

2)输出的各item可以当字符串,也可以是数值;当前记录的字段,变量或awk的表达式;数值会被隐式转换为字符串进行输出

字符串 item为字符串时需要使用" ",若将$1写入" "中,则不会引用awk内部变量 [root@sakura ~]# awk -F: '{print "kasumi:",$1,$3}' /etc/passwd kasumi: root 0 kasumi: bin 1 [root@sakura ~]# awk -F: '{print "kasumi:$1"}' /etc/passwd kasumi:$1 数值 item为数值时不需要" " [root@sakura ~]# awk -F: '{print 516,$1,$3}' /etc/passwd 516 root 0 516 bin 1 当前记录的字段 [root@sakura ~]# awk -F: '{print $1,$7}' /etc/passwd root /bin/bash bin /sbin/nologin 变量 ietm为变量时不需要使用$ [root@sakura ~]# awk -v path=kasumi 'BEGIN{print path}' kasumi 1234567891011121314151617

3)如果省略item,则相当于$0,即输出整行

[root@sakura ~]# awk -F: '{print}' /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin 123

4)输出空白字符:print “”

[root@sakura ~]# tail -2 /etc/passwd | awk '{print ""}'

ps:其表示为每处理一行信息,就输出空白字符

123

4.awk内建变量 1)FS:input field seperator,输入字段分隔符,与-F选项作用相同,默认为空白字符

[root@sakura ~]# awk -v FS=":" '{print $1,$3}' /etc/passwd root 0 bin 1 123

2)OFS:output field seperator,输出时分隔字符,默认为空白字符

[root@sakura ~]# awk -v FS=":" -v OFS=":" '{print $1,$3}' /etc/passwd root:0 bin:1 123

3)RS:input record seperator,输入时得换行符,默认为\n换行符

[root@sakura ~]# awk -v RS=":" '{print}' /etc/passwd root x 0 0 ps:文本本身自带的\n换行符也会启换行作用 123456

4)ORS:utput record seperator,输出时的换行符,默认为\n换行符

[root@sakura ~]# awk -v RS=":" -v ORS="#" '{print}' /etc/passwd root#x#0#0#root#/root#/bin/bash bin#x#1#1#bin#/bin#/sbin/nologin 123

5)NF:number of field,字段数量

1.NF 每行按分隔符计量的字段数 [root@sakura ~]# awk -F" " '{print NF}' /etc/fstab 0 1 2 2.$NF 表示仅显示每行最后一个字段,NF会被替换为每行的字段数量 [root@sakura ~]# awk -F" " '{print $NF}' /etc/fstab

# /etc/fstab 2019

1234567891011

6)NR:number of record,统计行数,即给每行显示行数;命令后跟的所有文件将统一合并计数

[root@sakura ~]# awk '{print NR}' /etc/fstab /etc/issue 1 2 3 ps:若命令后跟多个文件,其行数不会分别显示 12345

7)FNR:各文件分别计数;行数

[root@sakura ~]# awk '{print FNR}' /etc/fstab /etc/issue 1

8)FILENAME:当前文件名

[root@sakura ~]# awk '{print FILENAME}' /etc/issue /etc/issue /etc/issue /etc/issue [root@sakura ~]# awk 'FNR==1{print FILENAME}' /etc/issue /etc/fstab /etc/issue /etc/fstab ps:需要注意,指定文件有多少行,就会显示多少行文件名,使用操作符FNR==1可仅显示一行文件名 12345678

9)ARGC:命令行参数的个数

[root@sakura ~]# awk '{print ARGC}' /etc/fstab /etc/issue 3 12

10)ARGV:表示数组,保存的是命令行所给定的各个参数

[root@sakura ~]# awk 'NR==1{print ARGV[0]}' /etc/fstab /etc/issue awk [root@sakura ~]# awk 'NR==1{print ARGV[1]}' /etc/fstab /etc/issue /etc/fstab [root@sakura ~]# awk 'NR==1{print ARGV[2]}' /etc/fstab /etc/issue /etc/issue ps:程序段不会记录于其数组中 1234567

5.aw自定义变量 1)使用选项定义变量;-v var=value;变量名区分字符大小写

[root@sakura ~]# awk -v stars=yuki '{print stars}' /etc/issue yuki yuki yuki ps:这里文件内容未起作用,但是使用了文件的行数 12345

2)在program中直接定义变量

[root@sakura ~]# awk 'BEGIN{FS=":";f1=3}{print $f1}' /etc/passwd 0 1 [root@sakura ~]# awk 'BEGIN{stars="yuki";print stars}' yuki 12345

6.printf格式化输出命令:awk的输出命令之二 1)语法:printf FORMAT, item1, item2, …

1.FORMAT必须要给出 2.printf不会自动实现换行,需要显示给出换行控制符,\n 3.FORMAT中需要分别为后面的每个item指定一个格式化符号 123

2)格式符对照表

格式符含义%c显示字符的ASCII码%d,%i显示十进制整数%e,%E科学计数法数值显示%f显示为浮点数%g,%G以科学计数法或浮点形式显示数值%s显示为字符串%u显示为无符号整数%%显示%自身

3)修饰符

1.#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度;例如,%3.1f,显示为浮点数 2.-:表示左对齐 3.+:显示数值的符号 ps:默认为右对齐 1234

4)练习

使用printf控制符 [root@sakura ~]# awk -F: '{printf "usernmae:%s,UID:%d\n",$1,$3}' /etc/passwd usernmae:root,UID:0 usernmae:bin,UID:1 usernmae:daemon,UID:2 ps:运行时会将$1,$3分别对应至%s,%d上 123456 使用printf修饰符 [root@sakura ~]# awk -F: '{printf "usernmae: %-15s,UID: %d\n",$1,$3}' /etc/passwd usernmae: root ,UID: 0 usernmae: bin ,UID: 1 %-15s表示为,左对齐,%s的宽度为15 12345

7.操作符 1)算术操作符:

1.x+y, x-y, x*y, x/y, x^y, x%y 2.-x:转换为负数 3.+x:将字符串转换为数值 123

2)字符串操作符:没有符号的操作符,表示为字符串连接

3)赋值操作符

1.=, +=, -=, *=, /=, %=, ^= 2.++, -- 12

4)比较操作符

>, >=, <, <=, !=, == 1

5)模式匹配符

1.~:是否被模式所匹配 2.!~:是否被模式不匹配 12

6)逻辑操作符

1.&& 2.|| 3.! 123

7)函数调用

function_name(argu1,argu2,....) 1

8)条件表达式

selector?if-true-expression:if-false-expression 1

9)练习判断/etc/passwd文件中每个用户的UID,若其大于1000则显示common user,否则显示sysuser or sysadmin

[root@sakura ~]# awk -F: '{$3>=1000?usertype="common user":usertype="sysuser or sysadmin";printf "%15s:%-s\n",$1,usertype}' /etc/passwd root:sysuser or sysadmin bin:sysuser or sysadmin daemon:sysuser or sysadmin 1234

8.PATTERN:模式 1)empty:空模式,匹配所有行

2)/regular expression/:仅处理能够被此处的模式匹配到的行

[root@sakura ~]# awk '/^UUID/{print $1}' /etc/fstab UUID=366bd0a8-f2cc-4cc6-beaa-418dacdae36f UUID=274b447f-b701-439b-908a-f328de77cf63 UUID=f9fc6d2d-a8d1-4f08-9aba-8999f3da565c UUID=362e5f41-bc95-46ff-9902-d4e5c634ad99 [root@sakura ~]# awk '!/^UUID/{print $1}' /etc/fstab

# # [root@sakura ~]# awk -F: ‘/1/{print $1,$3}’ /etc/passwd bin 1 adm 3 abrt 173

12345678910111213

3)relational expression 关系表达式:结果有“真”或“假”;结果为“真”才会被处理; 结果为非0数值或非空字符串,即可认为是"真"

[root@sakura ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd nfsnobody 65534 yuki 1000 tom 1001 [root@sakura ~]# awk -F: '$1~/root/{print $1,$3}' /etc/passwd root 0 [root@sakura ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd root /bin/bash yuki /bin/bash [root@sakura ~]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd root /bin/bash yuki /bin/bash tom /bin/bash 12345678910111213

4)line ranges:行范围

1.startlin,endline:/part1/,/part2/ [root@sakura ~]# awk -F: '/^root/,/^adm/{print $1}' /etc/passwd root bin daemon adm 2.基于行数判断 [root@sakura ~]# awk -F: '(NR>=1&&NR<=5){print $1}' /etc/passwd root bin daemon adm lp ps:不支持直接给出数字的格式 1234567891011121314

5)BEGIN/END模式

1.BEGIN{}:仅在开始处理文件中的文本之前执行一次 2.END{}:仅在文本处理完成之后执行一次 [root@sakura ~]# awk -F: 'BEGIN{print " username uid \n-----------------"}{printf "%-10s %10d\n",$1,$3}END{print "===========\n end "}' /etc/passwd username uid ----------------- root 0 bin 1 daemon 2 . . . abc8 1013 abc9 1014 abc10 1015 =========== end 12345678910111213141516

9.常用的action

1.Expressions(表达式) 2.Control statements:if, while等 3.Compound statements:组合语句(将多个语句当做当个代码块运行,多个语句需要使用{}) 4.input statements 5.output statements 12345

二.控制语句

1.常用控制语句格式

1.if(条件:condition) {条件为真时语句:statments} 2.if(condition) {statments} else {statements} (双分支语句,组合语句中若有一个以上语句需要使用{},否则可以省略{}) 3.while(conditon) {statments} 4.do {statements} while(condition) (不论条件是否为真,都先循环一次循环体) 5.for(expr1;expr2;expr3) {statements} 6.break 7.continue 8.delete array[index] (从数组中删除指定语句) 9.delete array 10.exit (退出语句) 11.{ statements } 1234567891011

2.if-else语句:if(condition) {statement} else {statement} 1)判断/etc/passwd文件中每个用户的UID,若其大于1000则显示common user,否则显示sysuser or sysadmin

print打印 [root@sakura ~]# awk -F: '{if($3>=1000){print "common user:",$1,$3}else{print "sysuser or sysadmin:",$1,$3}}' /etc/passwd sysuser or sysadmin: root 0 sysuser or sysadmin: bin 1 common user: abc9 1014 common user: abc10 1015 printf打印 [root@sakura ~]# awk -F: '{if($3>=1000){printf "common user: %s,%d\n",$1,$3}else{printf "sysuser or sysadmin: %s,%d\n",$1,$3}}' /etc/passwd sysuser or sysadmin: root,0 sysuser or sysadmin: bin,1 sysuser or sysadmin: daemon,2 common user: abc9,1014 common user: abc10,1015 12345678910111213

2)判断/etc/passwd文件中每个用户的的bash是否为/bin/bash,并输出

[root@sakura ~]# awk -F: '{if($NF=="/bin/bash"){print $1,$NF}}' /etc/passwd root /bin/bash yuki /bin/bash tom /bin/bash 1234

3)判断/etc/fstab文件中每行的字段是否大于5,大于5的话则输出整行

[root@sakura ~]# awk '{if(NF>=5){print $0}}' /etc/fstab # Created by anaconda on Mon May 6 16:16:15 2019 # Accessible filesystems, by reference, are maintained under '/dev/disk' 123

4)判断df -h命令显示的文件系统用量中,已用量超过20%的分区,并显示之

[root@sakura ~]# df -h | awk -F% '/^\/dev/{print $1}' | awk '{if($NF>=20){print $1,$NF}}' /dev/sda3 44 /dev/sda2 26 123

ps:使用场景为,对awk取得的 整行或某个字段做条件判断

3.while循环:while(condition){statement};条件为真时进入循环,条件为假时,退出循环 1)判断/etc/grub2.cfg中,linux16开头的行中的每个单词的字符数

[root@sakura ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.673.10.67.2-el7 29 root=UUID=366bd0a8-f2cc-4cc6-beaa-418dacdae36f 46 ro 2 12345

2)判断/etc/grub2.cfg中,显示linux16开头的行中的每个单词的字符数大于等于7的单词

[root@sakura ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=7){print $i,length($i)};i++}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.673.10.67.2-el7 29 root=UUID=366bd0a8-f2cc-4cc6-beaa-418dacdae36f 46 crashkernel=auto 16 LANG=en_US.UTF-8 16 linux16 7 1234567

3)列出/etc/grub2.cfg文件中,当前系统可使用的内核,并对其编号

[root@sakura ~]# awk -F\' '/^menuentry/{print i++":",$2}' /etc/grub2.cfg 0: CentOS Linux (3.10.673.10.67.2-el7) 7 (Core) 1: CentOS Linux (3.10.67linux-3.10.67-1-el7) 7 (Core) 2: CentOS Linux (3.10.0-693.el7.x86_64) 7 (Core) 3: CentOS Linux (0-rescue-114408c9377741bc91b9e27df3c651f0) 7 (Core) 12345

ps:对一行内的多个字段逐一做类似处理时使用;对数组中的各元素逐一处理时使用 4.do-while循环:do {statement}while{condition} 1)意义为:在进入while循环前,至少运行一次循环体

5.for循环:for(expr1;expr2;expr3){statement} 1)语法:for(variable assignment;condition;iteration process) {for-body}

2)判断/etc/grub2.cfg中,linux16开头的行中的每个单词的字符数

[root@sakura ~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}' /etc/grub2.cfg linux16 7 /vmlinuz-3.10.673.10.67.2-el7 29 root=UUID=366bd0a8-f2cc-4cc6-beaa-418dacdae36f 46 ro 2 crashkernel=auto 16 123456

3)特殊用法:能够实现遍历数组中的元素

语法:for(var in array){for-body} 1

6.switch语句(类似bash shell中的case语句) 1)语法:switch(expression){case VALUE1 or /REGEXP/:statement;case VALUE2 or /REGEXP/:statement;…;default:statement} ps:VALUE1 or /REGEXP为变量值或正则表达式能匹配到的内容;default为当所有选项不匹配时,显示的结构

7.break和continue 1)break [n]:可跳出n层循环 2)continue:提前结束本轮循环,进入下轮循环

8.next:跳出awk的内置循环,即提前结束对本行的处理而直接进入下一行 1)输出/etc/passwd文件中用户ID为偶数的用户,使用next实现

[root@sakura ~]# awk -F: '{if($3%2!=0){next}else{print $1,$3}}' /etc/passwd root 0 daemon 2 lp 4 shutdown 6 mail 8 ps:使用awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd也可以实现 1234567

三.array数组

1.awk中一般使用关联数组:array[index-expression] 1)index-expression,数组索引

1.可使用任意字符串;字符串需要使用双引号 2.如果某数组元素实现不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串” 3.若需要判断数组中某元素是否存在,需要使用"index in array"格式进行,不能直接判断数组中的元素是否为空 [root@sakura ~]# awk 'BEGIN{role["riben"]="kasumi";role["china"]="wanglin";print role["riben"]}' kasumi [root@sakura ~]# awk 'BEGIN{role["riben"]="kasumi";role["china"]="wanglin";print role["china"]}' wanglin 1234567

2.若需要遍历数组中的每个元素,需要使用for循环 1)for(var in array){for-body}

[root@sakura ~]# awk 'BEGIN{role["riben"]="kasumi";role["china"]="wanglin";for(i in role){print role[i]}}' kasumi wanglin [root@sakura ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}' Tuesday Monday ps:var会遍历array的每一个索引 1234567

2)统计netstat -tan命令中tcp协议各个状态的出现次数

[root@sakura ~]# netstat -tan | awk '/^tcp\>/{stat[$NF]++}END{for(i in stat){print i,stat[i]}}' LISTEN 5 ESTABLISHED 3 123

3)统计/var/log/httpd/access_log文件中,各个ip访问的次数

[root@sakura ~]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log 192.168.3.19 72 12

4)统计/etc/fstab文件中每个文件系统类型出现的次数

[root@sakura ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab swap 1 xfs 3 123

5)统计指定文件中每个单词出现的次数

[root@sakura ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){print i,count[i]}}' /etc/fstab man 1 May 1 and/or 1 maintained 1 xfs 3 file 1 1234567

四.awk内置函数

1.数值处理:rand():返回0和1之间一个随机数

[root@sakura ~]# awk 'BEGIN{print rand()}' 0.237788 12

2.字符串处理 1)length([s]):返回指定字符串的长度 2)sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容

[root@sakura ~]# awk -F: '{print sub(o,O,$1)}' /etc/passwd 1 1 1 ps:显示结果为显示是否替换成功 12345

3)gsubsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容 4)split(s,a,[r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中

统计客户端访问http服务的次数 [root@sakura ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}' 192.168.3.19 3 0.0.0.0 5 1234

ps:awk也可使用自定义函数

</div>

ab ↩︎

最新回复(0)