文本处理工具之awk



本章内容:

  • awk介绍

  • awk基本用法

  • awk变量

  • awk格式化

  • awk操作符

  • awk条件判断

  • awk循环

  • awk数组

  • awk函数

  • 调用系统命令



1.awk介绍

★Linux 文本处理工具三剑客:

  • grep、sed、awk。其中grep是一种文本过滤工具;sed是文本行编辑器,而awk是一种报表生成器,就是对文件进行格式化处理的,但这里的格式化不是文件系统的格式化,而是对文件内容进行各种“排版”,进而格式化显示;

★在Linux之上我们使用的是GNU awk 简称gawk,并且gawk就是awk的链接文件,因此系统上使用的awk和gawk是一样的。我们通过man gawk可以获得gawk的相关功能说明---gawk-pattern scanning and processing language(模式扫描及处理语言),gawk是一种过程式编程语言。gawk还支持条件判断、数组、循环等编程语言中所有可以使用的功能,因此还可以把gawk称为一种脚本语言解释器。

 1.简介

★文本处理三工具:grep、sed、awk

  • grep,egrep,fgrep:文本过滤工具:partten

  • sed:行编辑器;模式空间、保持空间

  • awk:报告生成器,格式化文本输出;

★AWK

  • Aho, Weinberger, Kernighan,报告生成器,格式化文本输出;

  • 有多种版本:New awk(nawk),GNU awk(gawk);

  • gawk:模式扫描和处理语言;

[root@centos7 ~]# which awk
/usr/bin/awk
[root@centos7 ~]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 Jul 25 23:58 /usr/bin/awk -> gawk

★ 基本用法:

  • awk [options] ‘program’ var=value file…

  • awk [options] -f programfilevar=value file…

  • awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file ...

程序组成

  • awk程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成

用法说明

 1.用法格式,选项

★基本格式:awk [options] 'program' file…

program(编程语言):PATTERN{ACTION STATEMENT;..},通常是在单引号和双引号中;

  • PARTTERN: 模式;部分决定动作语句何时触发及触发事件(BEGIN,END)

  • ACTION STATEMENT:动作语句,可以由多个语句组成,各语句之间使用分号分隔:如print,printf

★options(选项):

  • -F:指明输入时用到的字段分隔符;

  • -v var=value: 自定义变量

★分割符、域和记录

  • awk执行时,由分隔符分隔的字段(域);标记$1,$2..$n称为域标识。$0为所有域,注意:和shell中变量$符含义不同

  • 文件的每一行称为记录

  • 省略action,则默认执行print $0 的操作。

 2.awk工作原理

 原理:

  • awk在处理文本时也是一次读取一行文本,然后根据输入分隔符(默认为空格字符)进行切片,切成n个片段,然后将每一片都赋予awk内部的一个变量当中进行保存,这些变量名为$1,$2,$3...等等一直到最后一个,awk就可以对这些片段进行单独处理,比如显示某一段,特定段,甚至可以对某些片段进行额外的的加工处理,比如计数、运算等。

具体工作原理如下:

  • 第一步:执行BEGIN{action;… }语句块中的语句;

  • 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

  • 第三步:当读至输入流末尾时,执行END{action;…}语句块

  • BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中

  • END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块

  • pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

演示:

[root@centos7 ~]# tail -5 /etc/fstab  # 取 /etc/fstab 的后五行
UUID=5de91e7f-4334-4646-8bcf-7e8df5969f74 /                       xfs     defaults        0 0
UUID=abad3f46-4294-40b0-9d48-78c7e87cbfbf /boot                   xfs     defaults        0 0
UUID=01aef744-48b5-4346-ab7d-33150e05f3c7 /usr                    xfs     defaults        0 0
UUID=9765d553-e77b-48db-a4ff-502e43833384 swap                    swap    defaults        0 0
UUID=a42aca7a-085a-43c2-a22c-4f4aa6a22574 /testdir                ext4    acl             0 0
[root@centos7 ~]# tail -5 /etc/fstab |awk '{print $2,$3}' # 对读进来的每一行都执行打印第2和第3片段
/ xfs
/boot xfs
/usr xfs
swap swap
/testdir ext4
[root@centos7 ~]# tail -5 /etc/fstab |awk '{print  "hello",$2,$3}'  # 自己加一个字段,注意要用逗号分隔
hello / xfs
hello /boot xfs
hello /usr xfs
hello swap swap
hello /testdir ext4

输出命令:print

print格式:print item1, item2, ...

要点:

  • 逗号分隔符;

  • 输出的各item可以是字符串,也可以是数值、当前记录的字段、变量或awk的表达式;

  • 如省略item,相当于print $0

演示:

[root@centos7 ~]# awk '{print "hello,awk"}' # 不管输入什么都只打印定义好的
asdas
hello,awk
asfas
hello,awk
dddd
hello,awk[root@centos7 ~]# awk -F: '{print}' /etc/passwd # 把/etc/passwd的每一行都打印一遍
root:x:0:0:tcpdump,,62985600:/root:/bin/bash
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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown[root@centos7 ~]# awk -F: '{print "tao"}' /etc/passwd # /etc/passwd 的每一行输入进去之后都打印成 tao
tao
tao
tao
tao
[root@centos7 ~]# awk -F: '{print $1}' /etc/passwd  # 以:为分隔符,打印每一行的第一个片段
root
bin
daemon
adm
lp[root@centos7 ~]# tail -5 /etc/fstab |awk '{print  "hello",$2,$3}'  # 自己加一个字段,注意要用逗号分隔
hello / xfs
hello /boot xfs
hello /usr xfs
hello swap swap
hello /testdir ext4[root@centos7 ~]# awk -F: '{print $1"\t"$3}' /etc/passwd  # 也可以用其他分隔符,但一定要加双引号。
root    0
bin 1
daemon  2
adm 3
lp  4
sync    5

awk变量

 1.内置和自定义变量

内置变量

◆FS:输入字段分隔符,默认为空白字符

  • awk -v FS=':'  '{print $1,$3,$7}' /etc/passwd

  • awk –F: '{print $1,$3,$7}' /etc/passwd

◆OFS:输出字段分隔符,默认为空白字符

  • awk -v FS=':' -v OFS=':' '{print $1,$2,$3}' /etc/passwd

◆RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效

  • awk -v RS=' ' ‘{print }’ /etc/passwd

◆ORS:输出记录分隔符,输出时用指定符号代替换行符

  • awk-v RS=' ' -v ORS='###'‘{print }’ /etc/passwd

◆NF:字段数量

  • awk -F:‘{print NF}’ /etc/fstab, 引用内置变量不用$

  • awk -F: '{print $(NF-1)}' /etc/passwd

◆NR:行号

  • awk '{print NR}' /etc/fstab; awk END'{print NR}' /etc/fstab

◆FNR:各文件分别计数,行号

  • awk '{print FNR}' /etc/fstab /etc/inittab

◆FILENAME:当前文件名

  • awk '{print FILENAME}’ /etc/fstab

◆ARGC:命令行参数的个数

  • awk '{print ARGC}’ /etc/fstab /etc/inittab

  • awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab

◆ARGV:数组,保存的是命令行所给定的各参数

  • awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab

  • awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab

自定义变量

-v var=value

  • 变量名区分字符大小写

在program中直接定义

awk -v test='hello gawk' '{print test}' /etc/fstab

awk -v test='hello gawk' 'BEGIN{print test}'

awk'BEGIN{test="hello,gawk";print test}'

内置变量演示:

[root@centos7 ~]# awk -F: '{print $1,$3,$7}' /etc/passwd  # 指明以“:”作为输入字段分隔符,如果不指明的话以空白当做分隔符
root 0 /bin/bash
bin 1 /sbin/nologin
daemon 2 /sbin/nologin
adm 3 /sbin/nologin
lp 4 /sbin/nologin
[root@centos7 ~]# awk -F: -v OFS='=>' '{print $1,$3,$7}' /etc/passwd  # 指明输入,输出字段分隔符
root=>0=>/bin/bash
bin=>1=>/sbin/nologin
daemon=>2=>/sbin/nologin
adm=>3=>/sbin/nologin
lp=>4=>/sbin/nologin
sync=>5=>/bin/sync[root@centos7 ~]# awk -F: -v ORS='###' '{print }' /etc/passwd # 指明输出是的换行符
root:x:0:0:tcpdump,,62985600:/root:/bin/bash###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###lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin###sync:x:5:0:sync:/sbin:/bin/sync###shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown[root@centos7 ~]# awk -F: '{print NF}' /etc/passwd  # 以:为分隔符,打印每一行的字段数量
7
7
7
7
7
7
7
7
7
[root@centos7 ~]# awk -F: '{print $NF}' /etc/passwd  # 这时,$NF=$7,因为NF为内之变量替换为7,所以会打印第7个字段
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin[root@centos7 ~]# awk '{print NR }' /etc/passwd   # 显示行号
1
2
3
4
5
6
7
[root@centos7 ~]# awk '{print FNR }' /etc/fstab /etc/issue
1     # 如果后面跟多个文件的话,要想显示每个文件的行数,变量为FNR,如果不加F,则行号累加
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
[root@centos7 ~]# awk END'{print NR }' /etc/fstab  # 显示最后一行的行号
13
[root@centos7 ~]# awk END'{print FNR }' /etc/fstab /etc/issue
6[root@centos7 ~]# awk '{print FILENAME}' /etc/fstab  # 显示当前文件名
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab[root@centos7 ~]# awk '{print ARGC}' /etc/fstab /etc/inittab # 命令行参数个数,但会输入的每行都会显示一遍
3
3
3
3
3
[root@centos7 ~]# awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
3        # 加上BEGIN 只显示一次命令行参数个数
[root@centos7 ~]# awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/inittab
awk      # 数组,显示的是命令行的第几个参数
[root@centos7 ~]# awk 'BEGIN {print ARGV[1]}' /etc/fstab /etc/inittab
/etc/fstab
[root@centos7 ~]# awk 'BEGIN {print ARGV[2]}' /etc/fstab /etc/inittab
/etc/inittab

自定义变量演示:

[root@centos7 ~]# awk -v test='hello gawk' '{print test}' /etc/fstab
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
hello gawk
[root@centos7 ~]# awk -v test='hello gawk' 'BEGIN{print test}' /etc/fstab
hello gawk# 直接在programe中以一个赋值语句给出变量也可以;
[root@centos7 ~]# awk 'BEGIN{test="hello,gawk";print test}'
hello,gawk

输出命令:printf

格式化输出:printf“FORMAT”, item1, item2, ...

  • 必须指定FORMAT;

  • 不会自动换行,需要显式给出换行控制符,\n;

  • FORMAT中需要分别为后面每个item指定格式符;

格式符:与item一一对应

  • %c:显示字符的ASCII码;

  • %d, %i:显示十进制整数;

  • %e, %E:科学计数法数值显示;

  • %f:显示为浮点数;

  • %g, %G:以科学计数法或浮点形式显示数值;

  • %s:显示字符串;

  • %u:无符号整数;

  • %%: 显示%自身;

修饰符:

  • #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f

  • -:左对齐(默认右对齐)%-15s

  • +:显示数值的正负符号%+d

演示:

[root@centos7 ~]# awk -F: '{printf "%s",$1}' /etc/passwd # 表示把$1的内容套在%s上,以字符串的形式显示;默认不自动换行;
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodyavahi-autoipdsystemd-bus-proxysystemd-networkdbuspolkitdabrtcolordlibstoragemgmtsetroubleshootrpcrtkitchronytssgeoclueusbmuxdmysqlpulsegdmrpcuserpostfixsshdntpapachetao[root@centos7 ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd  # 添加自动换行符
root
bin
daemon
adm
lp
sync
shutdown
halt[root@centos7 ~]# awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
Username: root      # 也可以添加字符串
Username: bin
Username: daemon
Username: adm
Username: lp
Username: sync
Username: shutdown[root@centos7 ~]# awk -F: '{printf "Username:%s UID:%d\n",$1,$3}' /etc/passwd
Username:root UID:0   # 格式和条目片段是对应的,每个片段会套在其对应的格式上
Username:bin UID:1
Username:daemon UID:2
Username:adm UID:3
Username:lp UID:4
Username:sync UID:5
Username:shutdown UID:6[root@centos7 ~]# awk -F: '{printf "Username:%15s UID:%d\n",$1,$3}' /etc/passwd
Username:           root UID:0     # 添加修饰符,显示宽度为15字符,默认为右对齐
Username:            bin UID:1
Username:         daemon UID:2
Username:            adm UID:3
Username:             lp UID:4
Username:           sync UID:5
Username:       shutdown UID:6
Username:           halt UID:7
[root@centos7 ~]# awk -F: '{printf "Username:%-15s UID:%d\n",$1,$3}' /etc/passwd
Username:root            UID:0     # 左对齐显示
Username:bin             UID:1
Username:daemon          UID:2
Username:adm             UID:3
Username:lp              UID:4
Username:sync            UID:5
Username:shutdown        UID:6

操作符

算数操作符:

  • x+y, x-y, x*y, x/y, x^y(x的y次方), x%y

  • -x:转换为负数;

  • +x:转换为数值;

字符串操作符:

  • 没有符号的操作符,字符串连接;

赋值操作符:

  • =, +=, -=, *=, /=, %=, ^=

  • ++, --

比较操作符:

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

模式匹配符:

  • ~:左边是否和右边匹配包含

  • !~:是否不匹配

示例:

  • cat /etc/passwd |awk '$0 ~ /root/' |wc -l

  • cat /etc/passwd |awk '$0 !~ /root/' |wc -l

逻辑操作符:&&,||,!

示例:

  • awk –F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd

  • awk -F: '$3 ==0 || $3>=1000 {print $1}' /etc/passwd

  • awk -F: ‘!($3==0){print $1}' /etc/passwd

  • awk -F: '!($3>=500) {print $3}}' /etc/passwd

函数调用:

  • function_name(argu1, argu2, ...)

条件表达式:

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

演示:

[root@centos7 ~]# awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf"%15s:%-s\n",$1,usertype}' /etc/passwdroot:Sysadmin or SysUser   # 显示用户的UID如果大等于1000则为普通用户,否则为管理员或系统用户,并定义格式输出bin:Sysadmin or SysUserdaemon:Sysadmin or SysUseradm:Sysadmin or SysUserlp:Sysadmin or SysUsersync:Sysadmin or SysUsershutdown:Sysadmin or SysUserhalt:Sysadmin or SysUsermail:Sysadmin or SysUseroperator:Sysadmin or SysUsergames:Sysadmin or SysUserftp:Sysadmin or SysUsernobody:Sysadmin or SysUseravahi-autoipd:Sysadmin or SysUser
systemd-bus-proxy:Sysadmin or SysUser
systemd-network:Sysadmin or SysUserdbus:Sysadmin or SysUserpolkitd:Sysadmin or SysUserabrt:Sysadmin or SysUsercolord:Sysadmin or SysUserlibstoragemgmt:Sysadmin or SysUsersetroubleshoot:Sysadmin or SysUserrpc:Sysadmin or SysUserrtkit:Sysadmin or SysUserchrony:Sysadmin or SysUsertss:Sysadmin or SysUsergeoclue:Sysadmin or SysUserusbmuxd:Sysadmin or SysUsermysql:Sysadmin or SysUserpulse:Sysadmin or SysUsergdm:Sysadmin or SysUserrpcuser:Sysadmin or SysUserpostfix:Sysadmin or SysUsersshd:Sysadmin or SysUserntp:Sysadmin or SysUserapache:Sysadmin or SysUsertao:Common User

PATTERN

 1.PATTERN:根据pattern条件,过滤匹配的行,再做处理

★如果未指定:

  • 空模式,匹配每一行

/regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来;

  • awk '/^UUID/{print $1}' /etc/fstab

  • awk '!/^UUID/{print $1}' /etc/fstab

relational expression: 关系表达式;

结果有“真”有“假”;结果为“真”才会被处理;

  • 真:结果为非0值,非空字符串;

  • 假:结果为空字符串;

line ranges:行范围

startline,endline:/pat1/,/pat2/不支持直接给出数字格式

  • awk -F: '/^root/,/^nobody/{print $1}' /etc/passwd

  • awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd

BEGIN/END 模式

  • BEGIN{}: 仅在开始处理文件中的文本之前执行一次

  • END{}:仅在文本处理完成之后执行一次

演示:

[root@centos7 ~]# awk '/^UUID/{print $1}' /etc/fstab  # 处理匹配到的模式
UUID=90880561-dca2-447b-a935-4c47e1bd03d8
UUID=219cc6c3-bd54-4bac-a47f-b498c491107f
UUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8d
UUID=af279379-acbd-47f5-a814-870666bdd6d1
[root@centos7 ~]# awk '!/^UUID/{print $1}' /etc/fstab  # 对匹配到的模式取反#
#
#
#
#
#
#
[root@centos7 ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534  # 关系表达式,也可以成为比较表达式,条件为真,才会被处理。题目表示,如果UID大于等于1000,则打印用户名和UID
tao 1000
[root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,$3}' /etc/passwd
root 0                    # 表示最后一个片段等于/bin/bash,然后符合的打印 用户名和UID
tao 1000
[root@centos7 ~]# awk -F: '$NF~/bash/ {print $1,$NF}' /etc/passwd
root /bin/bash           # 表示左边的值能够被右边的模式所匹配,
tao /bin/bash
[root@centos7 ~]# seq 10 |awk 'i=!i'
1
3
5
7
9
[root@centos7 ~]# awk -F: '/^root/,/^nobody/{print $1}' /etc/passwd
root    # 表示第一次被/^root/模式匹配到的行开始,到第一次被/^nobody/模式匹配到的行结束
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody[root@centos7 ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
bin      # 表示第二行到第十行,打印用户名
daemon
adm
lp
sync
shutdown
halt
mail
operator
[root@centos7 ~]# awk -F: 'BEGIN{print "   username   uid   \n----------------------"}'username   uid
----------------------      # 打印表头[root@centos7 ~]# awk -F: 'BEGIN{print "           username   uid   \n--------------------------"}{printf "%18s %3d\n",$1,$3}' /etc/passwdusername   uid
--------------------------root   0bin   1daemon   2adm   3lp   4sync   5shutdown   6
[root@centos7 ~]# awk -F: 'BEGIN{print "  username   uid   \n--------------------------"}{print $1,$3}END{print "=======================\n       END"}' /etc/passwd username   uid
--------------------------
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
dbus 81
polkitd 997
abrt 173
colord 996
tcpdump 72
tao 1000
=======================END

常用的action

  • Expressions:算术,比较表达式等

  • Control statements: 控制语句 if, while等

  • Compound statements: 组合语句

  • input statements:输入语句

  • output statements: 输出语句 print等

awk控制语句

  • { statements;… } 组合语句

  • if(condition) {statements;…}

  • if(condition) {statements;…} else {statements;…}

  • while(conditon) {statments;…}

  • do {statements;…} while(condition)

  • for(expr1;expr2;expr3) {statements;…}

  • break

  • continue

  • delete array[index]

  • delete array

  • exit

 1.awk控制语句:if-else

语法:

  • if(condition) statement [else statement]

  • if(condition1){statement1} else if(condition2)

{statement 2}else{statement3}

使用场景:

  • 对awk取得的整行或某个字段做条件判断

命令演示:

[root@centos7 ~]# awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd # 单分支语句
nfsnobody 65534
tao 1000
[root@centos7 ~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
root or Sysuser: root    # 双分支语句,一定注意语法书写格式!!!
root or Sysuser: bin
root or Sysuser: daemon
root or Sysuser: adm
root or Sysuser: lp
root or Sysuser: sync
root or Sysuser: shutdown
root or Sysuser: halt
root or Sysuser: mail
root or Sysuser: operator
root or Sysuser: games
root or Sysuser: ftp
root or Sysuser: nobody
root or Sysuser: avahi-autoipd
root or Sysuser: systemd-bus-proxy
root or Sysuser: systemd-network
root or Sysuser: dbus
root or Sysuser: polkitd
root or Sysuser: abrt
root or Sysuser: colord
root or Sysuser: libstoragemgmt
root or Sysuser: setroubleshoot
root or Sysuser: rpc
root or Sysuser: rtkit
root or Sysuser: chrony
root or Sysuser: tss
root or Sysuser: geoclue
root or Sysuser: usbmuxd
root or Sysuser: mysql
root or Sysuser: pulse
root or Sysuser: gdm
root or Sysuser: rpcuser
Common user: nfsnobody
root or Sysuser: postfix
root or Sysuser: sshd
root or Sysuser: ntp
root or Sysuser: tcpdump
Common user: tao
[root@centos7 ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
root     # 对某个字段做条件判断
tao
[root@centos7 ~]# awk '{if(NF>5) print $0}' /etc/fstab  # 如果字段大于5,就打印
# Created by anaconda on Tue Aug 30 09:45:37 2016
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
UUID=90880561-dca2-447b-a935-4c47e1bd03d8 /                       xfs     defaults        0 0
UUID=219cc6c3-bd54-4bac-a47f-b498c491107f /boot                   xfs     defaults        0 0
UUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8d /usr                    xfs     defaults        0 0
UUID=af279379-acbd-47f5-a814-870666bdd6d1 swap                    swap    defaults        0 0

取磁盘利用率:

[root@centos7 ~]# df -h |awk -F[%] '{print $1}' # 以%为分隔符,取第一字段
Filesystem      Size  Used Avail Use
/dev/sda2        40G  915M   40G   3
devtmpfs        475M     0  475M   0
tmpfs           489M     0  489M   0
tmpfs           489M  6.7M  483M   2
tmpfs           489M     0  489M   0
/dev/sda3        20G  2.8G   18G  14
/dev/sda1       485M  138M  348M  29
tmpfs            98M     0   98M   0
[root@centos7 ~]# df -h |awk -F[%] '{print $1}' |awk '{print $NF}'
Use                                       # 再取最后一个字段
3
0
0
2
0
14
29
0
[root@centos7 ~]# df -h |awk -F[%] '/^\/dev/{print $1}' |awk '{print $1,$NF}'
/dev/sda2 3                       # 模式匹配,匹配 以/dev开头的行,注意这里要对/ 转义,模式匹配一定要写在 “/ /”中
/dev/sda3 14
/dev/sda1 29
[root@centos7 ~]# df -h |awk -F[%] '/^\/dev/{print $1}' |awk '{if($NF>=20) print $1}'
/dev/sda1   # 如果利用率大于等于20,就打印第一字段

2.awk控制语句:while循环

★语法:

  • while(condition) statement

条件“真”,进入循环;条件“假”,退出循环;

使用场景:

  • 对一行内的多个字段逐一类似处理时使用;

  • 对数组中的各元素逐一处理时使用;

[root@centos7 ~]# awk '/[[:space:]]*linux16/{print}' /etc/grub2.cfg  # 取文件模式所匹配的行linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 ro rhgb quiet LANG=en_US.UTF-8linux16 /vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 ro rhgb quiet
[root@centos7 ~]# awk '/[[:space:]]*linux16/{print NF}' /etc/grub2.cfg
7                      # 所匹配行的字段数量
6[root@centos7 ~]# awk '/[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++ }}' /etc/grub2.cfg   # 对每一行字段中包含的字符长度做统计。 这里用到了while循环,当i小于等于字段数量,是就执行打印这一字段,及字段长短,并且执行i++,注意循环体用{}括起来
linux16 7
/vmlinuz-3.10.0-327.el7.x86_64 30
root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50
root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
ro 2
rhgb 4
quiet 5
# 在上题的基础之上嵌套了一个if语句,表示如果字符长度大于7才打印,注意这里的{}表示的意义,最外面一层是整个的处理语句,倒数第二层表示循环体,最里面的表示if语句的执行动作,i++是while语句的,用分号分开
[root@centos7 ~]# 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.0-327.el7.x86_64 30
root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50
root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46

 3.awk控制语句:do-while循环

语法:

  • do statement while(condition)

意义:

  • 无论真假,至少执行一次循环体

演示:

[root@centos7 ~]# awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
5050

 4.awk控制语句:for循环

语法:for(expr1;expr2;expr3) statement

  • for(variable assignment;condition;iterationprocess) {for-body}

特殊用法:能够遍历数组中的元素;

  • 语法:for(varin array) {for-body}

[root@centos7 ~]# awk '/[[:space:]]*linux16/ {for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-327.el7.x86_64 30
root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50
root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
ro 2
rhgb 4
quiet 5
[root@centos7 ~]# awk '/[[:space:]]*linux16/ {for(i=1;i<=NF;i++) {if(length($i)>=7) print $i,length($i)}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-327.el7.x86_64 30
root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50
root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46

 5.awk控制语句:switch语句

语法:

  • switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}

 6.break和continue

  • break [n]

  • continue [n]

 7.next

提前结束对本行处理而直接进入下一行处理(awk自身循环)

命令演示:

[root@centos7 ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
root 0    # 表示用户的ID号如果不为偶数,就提前终止这一行,直接进入下一行处理。
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
avahi-autoipd 170
systemd-network 998
colord 996
setroubleshoot 994
rpc 32
rtkit 172
geoclue 992
gdm 42
nfsnobody 65534
sshd 74
ntp 38
tcpdump 72
tao 1000[root@centos7 ~]# awk -F: '{if($3%2==0) print $1,$3}' /etc/passwd
root 0           # 和上面表示的结果是相同的,但方法和意义不同
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
avahi-autoipd 170
systemd-network 998
colord 996
setroubleshoot 994
rpc 32
rtkit 172
geoclue 992
gdm 42
nfsnobody 65534
sshd 74
ntp 38
tcpdump 72
tao 1000

awk数组

关联数组:

  • array [index-expression]

index-expression:

  • 可使用任意字符串;字符串要使用双引号括起来

  • 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”

若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历

若要遍历数组中的每个元素,要使用for循环

  • for(varin array) {for-body}

注意:var会遍历array的每个索引

示例:

  • awk'{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log

[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekday["tue"]="Tuesday";print weekdays["mon"]}'
Monday
[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["tue"]}'
Tuesday

遍历数组中的每个元素:for

[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
Tuesday
Monday
[root@centos7 ~]# netstat -tan |awk '/^tcp\>/{print}'
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:6010          0.0.0.0:*               LISTEN
tcp        0     52 10.1.249.203:22         10.1.250.25:51498       ESTABLISHED# 本题为第二种情况,数组元素事先不存在,在引用时,awk会自动创建此元素,其初始值为“空串”也就是0。题目中,$NF变量作为数组的索引下标,其个数,出现一次就自加,自加的结果为数组元素
的值;定义的for循环中的变量i为数组中的索引下标,state[i]才是数组中元素的值,最后打印数
组中的索引下标和数组元素。[root@centos7 ~]# netstat -tan |awk '/^tcp\>/{state[$NF]++}END{for(i in state) {print i,state[i]}}'
LISTEN 4
ESTABLISHED 1


练习:

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

[root@centos7 ~]# awk '/^UUID/{print}' /etc/fstab
UUID=90880561-dca2-447b-a935-4c47e1bd03d8 /                       xfs     defaults        0 0
UUID=219cc6c3-bd54-4bac-a47f-b498c491107f /boot                   xfs     defaults        0 0
UUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8d /usr                    xfs     defaults        0 0
UUID=af279379-acbd-47f5-a814-870666bdd6d1 swap                    swap    defaults        0 0
[root@centos7 ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
swap 1
xfs 3

2.统计指定文件中每个单词出现的次数(行内字段遍历)

# 因为是对整个文件做遍历,所以不用过滤行,然后遍历每一行中单词(默认空格分隔为一个单词)出现的个数,最后打印索引下标和元素个数
[root@centos7 ~]# awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab
Tue 1
man 1
and/or 1
maintained 1
xfs 3
Accessible 1
# 7
30 1
are 1
defaults 4
UUID=219cc6c3-bd54-4bac-a47f-b498c491107f 1
blkid(8) 1
/ 1

awk函数

数值处理:

  • rand():返回0和1之间一个随机数

字符串处理:

  • length([s]):返回指定字符串的长度

  • sub(r,s,[t]):在t字符串搜索能够被r表示的模式所匹配的内容,并将第一个匹配的内容替换为s;

  • gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容

  • split(s,array,[r]):以r为分隔符切割字符s,并将切割后的结果保存至array所表示的数组中

示例:

 # 数值处理,rand()示例
[root@centos7 ~]# awk 'BEGIN{print rand()}'
0.237788
[root@centos7 ~]# awk 'BEGIN{print rand()}'
0.237788
[root@centos7 ~]# awk 'BEGIN{print rand()}'
0.237788
[root@centos7 ~]# awk 'BEGIN{print rand()}'
0.237788
[root@centos7 ~]# awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
51
40
86
36
75
30
14
7
58
96
# 把第一个字段(2008:08:08)中第一次查找到的 :替换为“”空,
[root@centos7 ~]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"",$1)'
200808:08 08:08:08#把第一个字段中所有的 :替换为空
[root@centos7 ~]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"",$1)'
20080808 08:08:08
[root@centos7 ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");print ip[1]}'
0.0.0.0
0.0.0.0
0.0.0.0
0.0.0.0
10.1.250.25# 相当于嵌套了一个数组,对ip[1]数组中的元素做统计
[root@centos7 ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) print i,count[i]}'
0.0.0.0 4
10.1.250.25 1

转载于:https://blog.51cto.com/1992tao/1855972

文本处理三剑客之gawk相关推荐

  1. linux 下 grep -c sh* /etc/passwd,Linux文本处理三剑客--grep

    稍微接触过linux都会知道有三个非常强大文本处理工具,那就是grep.sed和awk,想必都有听说过吧. Linux文本处理三剑客: grep, egrep, fgrep:文本过滤工具(模式:pat ...

  2. GNU awk 的用法-文本处理三剑客之一

    GNU awk 的用法 awk 简介 文本处理三剑客 awk 工作原理 awk 用法 1.print 2.变量 2.1 内建变量 2.2 自定义变量 3.printf 命令 4.操作符 4.1 算术操 ...

  3. Linux文本处理三剑客之sed

    推荐新手阅读[酷壳]或[骏马金龙]开篇的教程作为入门.骏马兄后面的文章以及官方英文文档较难. [酷壳]:https://coolshell.cn/articles/9104.html [骏马金龙-博客 ...

  4. 文本处理三剑客之sed(流编辑器)

    文本处理三剑客之sed(流编辑器) - 行编辑器 把当前处理的行存储在临时缓冲区,称为模式空间,然后把模式空间的内容送往屏幕,一行一行的处理,主要用来编辑一个或者多个文件. - 用法 sed [opt ...

  5. THU.文本处理三剑客

    THU.文本处理三剑客 文本处理三剑客 Sed 流式编辑器,主要擅长对文件的编辑操作,我们可以事先定制好编辑文件的指令,然后让sed自动完成对文件的整体编辑 # 用法 sed 选项 '定位+命令' 文 ...

  6. 文本处理三剑客之 sed 流编辑器(基础部分)

    文本处理三剑客之 sed 流编辑器(基础部分) SED 即 Stream EDitor.和交互式编辑器如 vi 需要打开整个文件不同,sed 是行编辑器,每次处理一行,比较适合在脚本中进行无交互编辑, ...

  7. shell学习心得笔记系列一 文本处理三剑客

    理解 整理自网络资料,非原创版权,只用于学习理解的笔记和资料,禁止侵权 shell语言的理解:重点在于它是一个解释型语言,学习的shell语法写出的shell脚本,最终由linux服务器的解释器逐句解 ...

  8. 文本处理三剑客之 awk

    GAWK:报告生成器,格式化文本输出 awk [options] 'program' var=value file- awk [options] -f programfile var=value fi ...

  9. linux100day(day4)--文本处理三剑客

    在介绍三剑客之前,先来认识一下通配符和正则表达式 通配符 正则表达式 作用:通过一些特殊字符,来表示一类字符内容 1.字符匹配 .     任意一个字符 [ ]   范围内的任意一个字符 [^ ] 取 ...

  10. 9、Linux文本处理三剑客之sed命令

    Linux 用于处理文本数据的三剑客,分别为 grep 命令.awk 命令和 sed 命令,再加上正则表达式,就可以处理文本文件中各种常见的数据需求了.一般来说,grep 命令倾向于查找,sed 命令 ...

最新文章

  1. 惊闻谢文离职雅虎中国
  2. 近视手术─医学界的一个阴谋? !
  3. java中对象排序_java中 对象的排序
  4. SDAutoLayout 一行代码搞定自动布局
  5. loadrunner提高篇 - 关联技术的经典使用
  6. 免费资源下载:超酷超全的PSD按钮资源
  7. 百行征信出首招,发布授信 反欺诈 核验三款测试产品
  8. .xmind用什么软件打开_swf文件用什么打开 怎么把swf转换成mp4
  9. Python基础实战之文字游戏——模拟武侠类场景中的两派战斗场面
  10. 为什么很多公司不要培训出来的Java程序员?
  11. 香蕉树上第十根芭蕉——深度好文-为什么要写博客
  12. spark 集群处理后转单机pyspark 或 pands 数据处理 的方法
  13. 商品期货可以做长线吗(期货交易可以做长线吗)
  14. 使用py对Excel表格进行基本读写操作
  15. 使用 AutoHotKey 配合Win10分屏功能
  16. 有哪些高含金量的编程竞赛?
  17. 焦深(depth of focus)
  18. java swt 双屏_YOTA3手机和kindle合二为一,让你玩的同时享受阅读的乐趣
  19. 5g基站服务器需要芯片吗,华为发布业内5G基站的核心“天罡芯片”,估计他们肠子都悔青了吧...
  20. 三大场景、四大趋势:平安区块链平台与金融壹账通的实践总结

热门文章

  1. python dictionay(字典 )基本用法
  2. WEB应用程序--概述
  3. 为什么手工drop_caches之后cache值并未减少?
  4. 深入解读Linux内存管理系列(3)——MMU初始化和页表的建立
  5. linux内存源码分析 - 内存池
  6. 如何提高Android系统Aututu benchmark跑分
  7. 统计难题 HDU - 1251(字典树)
  8. android sdk 转移_腾讯微博java(android)sdk关系链api详细介绍
  9. spark 两个rdd求交集,差集,并集
  10. hadoop2.4.1源码在64位系统编译过程中遇到的几个错误及解决方法