awk

  • 时间:
  • 来源:互联网
原文链接:https://blog.csdn.net/Kasumi_yuki/article/details/91057975
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Kasumi_yuki/article/details/91057975

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"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

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

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:其输出时默认的分隔符为空白字符
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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
  • 1
  • 2
  • 3

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

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

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

  • 1
  • 2
  • 3

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

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

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

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

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

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

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
  • 1
  • 2
  • 3

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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

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

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可仅显示一行文件名
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

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

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:程序段不会记录于其数组中
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

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

2)在program中直接定义变量

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

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

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

2)格式符对照表

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

3)修饰符

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

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上
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
使用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
  • 1
  • 2
  • 3
  • 4
  • 5

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

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

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

3)赋值操作符

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

4)比较操作符

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

5)模式匹配符

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

6)逻辑操作符

1.&&
2.||
3.!
  • 1
  • 2
  • 3

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
  • 1
  • 2
  • 3
  • 4

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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:不支持直接给出数字的格式
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

9.常用的action

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

二.控制语句

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 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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
  • 1
  • 2
  • 3
  • 4

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'
  • 1
  • 2
  • 3

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
  • 1
  • 2
  • 3

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
  • 1
  • 2
  • 3
  • 4
  • 5

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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)
  • 1
  • 2
  • 3
  • 4
  • 5

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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也可以实现
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

三.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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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的每一个索引
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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
  • 1
  • 2
  • 3

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
  • 1
  • 2

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

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

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

四.awk内置函数

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

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

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:显示结果为显示是否替换成功
  • 1
  • 2
  • 3
  • 4
  • 5

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
  • 1
  • 2
  • 3
  • 4

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

                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-b6c3c6d139.css" rel="stylesheet">
                </div>

  1. ab ↩︎

本文链接http://element-ui.cn/news/show-423.html