文本处理工具之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/awklrwxrwxrwx. 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 0UUID=abad3f46-4294-40b0-9d48-78c7e87cbfbf /boot xfs defaults 0 0UUID=01aef744-48b5-4346-ab7d-33150e05f3c7 /usr xfs defaults 0 0UUID=9765d553-e77b-48db-a4ff-502e43833384 swap swap defaults 0 0UUID=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 xfsswap 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"}' # 不管输入什么都只打印定义好的asdashello,awkasfashello,awkddddhello,awk[root@centos7 ~]# awk -F: '{print}' /etc/passwd # 把/etc/passwd的每一行都打印一遍root:x:0:0:tcpdump,,62985600:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdown[root@centos7 ~]# awk -F: '{print "tao"}' /etc/passwd # /etc/passwd 的每一行输入进去之后都打印成 taotaotaotaotao[root@centos7 ~]# awk -F: '{print $1}' /etc/passwd # 以:为分隔符,打印每一行的第一个片段rootbindaemonadmlp[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 0bin 1daemon 2adm 3lp 4sync 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/bashbin 1 /sbin/nologindaemon 2 /sbin/nologinadm 3 /sbin/nologinlp 4 /sbin/nologin[root@centos7 ~]# awk -F: -v OFS='=>' '{print $1,$3,$7}' /etc/passwd # 指明输入,输出字段分隔符root=>0=>/bin/bashbin=>1=>/sbin/nologindaemon=>2=>/sbin/nologinadm=>3=>/sbin/nologinlp=>4=>/sbin/nologinsync=>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 # 以:为分隔符,打印每一行的字段数量777777777[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 # 显示行号1234567[root@centos7 ~]# awk '{print FNR }' /etc/fstab /etc/issue1 # 如果后面跟多个文件的话,要想显示每个文件的行数,变量为FNR,如果不加F,则行号累加2345678910111213123456[root@centos7 ~]# awk END'{print NR }' /etc/fstab # 显示最后一行的行号13[root@centos7 ~]# awk END'{print FNR }' /etc/fstab /etc/issue6[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 # 命令行参数个数,但会输入的每行都会显示一遍33333[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/fstabhello gawkhello gawkhello gawkhello gawkhello gawkhello gawkhello gawkhello gawkhello gawkhello gawkhello gawkhello gawkhello gawk[root@centos7 ~]# awk -v test='hello gawk' 'BEGIN{print test}' /etc/fstabhello 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 # 添加自动换行符rootbindaemonadmlpsyncshutdownhalt[root@centos7 ~]# awk -F: '{printf "Username: %s\n",$1}' /etc/passwd Username: root # 也可以添加字符串Username: binUsername: daemonUsername: admUsername: lpUsername: syncUsername: shutdown[root@centos7 ~]# awk -F: '{printf "Username:%s UID:%d\n",$1,$3}' /etc/passwdUsername:root UID:0 # 格式和条目片段是对应的,每个片段会套在其对应的格式上Username:bin UID:1Username:daemon UID:2Username:adm UID:3Username:lp UID:4Username:sync UID:5Username:shutdown UID:6[root@centos7 ~]# awk -F: '{printf "Username:%15s UID:%d\n",$1,$3}' /etc/passwdUsername: root UID:0 # 添加修饰符,显示宽度为15字符,默认为右对齐Username: bin UID:1Username: daemon UID:2Username: adm UID:3Username: lp UID:4Username: sync UID:5Username: shutdown UID:6Username: halt UID:7[root@centos7 ~]# awk -F: '{printf "Username:%-15s UID:%d\n",$1,$3}' /etc/passwdUsername:root UID:0 # 左对齐显示Username:bin UID:1Username:daemon UID:2Username:adm UID:3Username:lp UID:4Username:sync UID:5Username: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/passwd root:Sysadmin or SysUser # 显示用户的UID如果大等于1000则为普通用户,否则为管理员或系统用户,并定义格式输出 bin:Sysadmin or SysUser daemon:Sysadmin or SysUser adm:Sysadmin or SysUser lp:Sysadmin or SysUser sync:Sysadmin or SysUser shutdown:Sysadmin or SysUser halt:Sysadmin or SysUser mail:Sysadmin or SysUser operator:Sysadmin or SysUser games:Sysadmin or SysUser ftp:Sysadmin or SysUser nobody:Sysadmin or SysUser avahi-autoipd:Sysadmin or SysUsersystemd-bus-proxy:Sysadmin or SysUsersystemd-network:Sysadmin or SysUser dbus:Sysadmin or SysUser polkitd:Sysadmin or SysUser abrt:Sysadmin or SysUser colord:Sysadmin or SysUser libstoragemgmt:Sysadmin or SysUser setroubleshoot:Sysadmin or SysUser rpc:Sysadmin or SysUser rtkit:Sysadmin or SysUser chrony:Sysadmin or SysUser tss:Sysadmin or SysUser geoclue:Sysadmin or SysUser usbmuxd:Sysadmin or SysUser mysql:Sysadmin or SysUser pulse:Sysadmin or SysUser gdm:Sysadmin or SysUser rpcuser:Sysadmin or SysUser postfix:Sysadmin or SysUser sshd:Sysadmin or SysUser ntp:Sysadmin or SysUser apache:Sysadmin or SysUser tao: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-4c47e1bd03d8UUID=219cc6c3-bd54-4bac-a47f-b498c491107fUUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8dUUID=af279379-acbd-47f5-a814-870666bdd6d1
[root@centos7 ~]# awk '!/^UUID/{print $1}' /etc/fstab # 对匹配到的模式取反#######
[root@centos7 ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwdnfsnobody 65534 # 关系表达式,也可以成为比较表达式,条件为真,才会被处理。题目表示,如果UID大于等于1000,则打印用户名和UIDtao 1000
[root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,$3}' /etc/passwdroot 0 # 表示最后一个片段等于/bin/bash,然后符合的打印 用户名和UIDtao 1000[root@centos7 ~]# awk -F: '$NF~/bash/ {print $1,$NF}' /etc/passwdroot /bin/bash # 表示左边的值能够被右边的模式所匹配,tao /bin/bash
[root@centos7 ~]# seq 10 |awk 'i=!i'13579
[root@centos7 ~]# awk -F: '/^root/,/^nobody/{print $1}' /etc/passwdroot # 表示第一次被/^root/模式匹配到的行开始,到第一次被/^nobody/模式匹配到的行结束bindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobody[root@centos7 ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwdbin # 表示第二行到第十行,打印用户名daemon admlpsyncshutdownhaltmailoperator
[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/passwd username uid -------------------------- root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6
[root@centos7 ~]# awk -F: 'BEGIN{print " username uid \n--------------------------"}{print $1,$3}END{print "=======================\n END"}' /etc/passwd username uid --------------------------root 0bin 1daemon 2adm 3lp 4sync 5dbus 81polkitd 997abrt 173colord 996tcpdump 72tao 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 65534tao 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: binroot or Sysuser: daemonroot or Sysuser: admroot or Sysuser: lproot or Sysuser: syncroot or Sysuser: shutdownroot or Sysuser: haltroot or Sysuser: mailroot or Sysuser: operatorroot or Sysuser: gamesroot or Sysuser: ftproot or Sysuser: nobodyroot or Sysuser: avahi-autoipdroot or Sysuser: systemd-bus-proxyroot or Sysuser: systemd-networkroot or Sysuser: dbusroot or Sysuser: polkitdroot or Sysuser: abrtroot or Sysuser: colordroot or Sysuser: libstoragemgmtroot or Sysuser: setroubleshootroot or Sysuser: rpcroot or Sysuser: rtkitroot or Sysuser: chronyroot or Sysuser: tssroot or Sysuser: geoclueroot or Sysuser: usbmuxdroot or Sysuser: mysqlroot or Sysuser: pulseroot or Sysuser: gdmroot or Sysuser: rpcuserCommon user: nfsnobodyroot or Sysuser: postfixroot or Sysuser: sshdroot or Sysuser: ntproot or Sysuser: tcpdumpCommon user: tao
[root@centos7 ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwdroot # 对某个字段做条件判断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 infoUUID=90880561-dca2-447b-a935-4c47e1bd03d8 / xfs defaults 0 0UUID=219cc6c3-bd54-4bac-a47f-b498c491107f /boot xfs defaults 0 0UUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8d /usr xfs defaults 0 0UUID=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 3devtmpfs 475M 0 475M 0tmpfs 489M 0 489M 0tmpfs 489M 6.7M 483M 2tmpfs 489M 0 489M 0/dev/sda3 20G 2.8G 18G 14/dev/sda1 485M 138M 348M 29tmpfs 98M 0 98M 0[root@centos7 ~]# df -h |awk -F[%] '{print $1}' |awk '{print $NF}'Use # 再取最后一个字段3002014290[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-8 linux16 /vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 ro rhgb quiet[root@centos7 ~]# awk '/[[:space:]]*linux16/{print NF}' /etc/grub2.cfg7 # 所匹配行的字段数量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 30root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46ro 2rhgb 4quiet 5LANG=en_US.UTF-8 16linux16 7/vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46ro 2rhgb 4quiet 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.cfglinux16 7/vmlinuz-3.10.0-327.el7.x86_64 30root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46LANG=en_US.UTF-8 16linux16 7/vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50root=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.cfglinux16 7/vmlinuz-3.10.0-327.el7.x86_64 30root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46ro 2rhgb 4quiet 5LANG=en_US.UTF-8 16linux16 7/vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46ro 2rhgb 4quiet 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 30root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46LANG=en_US.UTF-8 16linux16 7/vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50root=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/passwdroot 0 # 表示用户的ID号如果不为偶数,就提前终止这一行,直接进入下一行处理。daemon 2lp 4shutdown 6mail 8games 12ftp 14avahi-autoipd 170systemd-network 998colord 996setroubleshoot 994rpc 32rtkit 172geoclue 992gdm 42nfsnobody 65534sshd 74ntp 38tcpdump 72tao 1000[root@centos7 ~]# awk -F: '{if($3%2==0) print $1,$3}' /etc/passwdroot 0 # 和上面表示的结果是相同的,但方法和意义不同daemon 2lp 4shutdown 6mail 8games 12ftp 14avahi-autoipd 170systemd-network 998colord 996setroubleshoot 994rpc 32rtkit 172geoclue 992gdm 42nfsnobody 65534sshd 74ntp 38tcpdump 72tao 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]}}'TuesdayMonday
[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 4ESTABLISHED 1
练习:
1.统计/etc/fstab文件中每个文件系统类型出现的次数
[root@centos7 ~]# awk '/^UUID/{print}' /etc/fstabUUID=90880561-dca2-447b-a935-4c47e1bd03d8 / xfs defaults 0 0UUID=219cc6c3-bd54-4bac-a47f-b498c491107f /boot xfs defaults 0 0UUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8d /usr xfs defaults 0 0UUID=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/fstabswap 1xfs 3
2.统计指定文件中每个单词出现的次数(行内字段遍历)
# 因为是对整个文件做遍历,所以不用过滤行,然后遍历每一行中单词(默认空格分隔为一个单词)出现的个数,最后打印索引下标和元素个数[root@centos7 ~]# awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstabTue 1man 1and/or 1maintained 1xfs 3Accessible 1# 730 1are 1defaults 4UUID=219cc6c3-bd54-4bac-a47f-b498c491107f 1blkid(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) }'5140863675301475896
# 把第一个字段(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.00.0.0.00.0.0.00.0.0.010.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 410.1.250.25 1