欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

Awk

程序员文章站 2022-07-01 22:22:30
AWK:awk介绍: Linux 文本处理工具三剑客:grep、sed、awk 其中grep是一种文本过滤工具,sed是文本行编辑器,而awk是一种报表生成器,就是对文件进行格式化处理的,但这里的格式化不是文件系统的格式化,而是对文件内容进行各种"排版",进而格式化显示 在Linux之上我们使用的是 ......

awk:
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称为一种脚本语言解释器。

  grep、egrep、fgrep:文本过滤工具:partten
  sed:行编辑器;模式空间、保持空间
  awk:报告生成器,格式化文本输出

  awk:aho, weinberger, kernighan,报告生成器,格式化文本输出
  有多种版本:new awk(nawk)、gnu awk(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 programfile var=value file…
  awk [options] 'begin{ action;… } pattern{ action;… } end{ action;… }' file ...
 程序组成:awk程序通常由:begin语句块、能够使用模式匹配的通用语句块、end语句块,共3部分组成

  用法格式及选项:
  基本格式:awk [options] 'program' file…
  options(选项):
    -f 指明输入时用到的字段分隔符
   -v var=value 自定义变量

  program(编程语言):pattern{action statement;...},通常是在单引号和双引号中
    parttern 模式,部分决定动作语句何时触发及触发事件(begin、end)
    action statement 动作语句,可以由多个语句组成,各语句之间使用分号分隔:如print;printf

  分割符、域和记录:
  awk执行时,由分隔符分隔的字段(域);标记$1,$2..$n称为域标识。$0为所有域;注意:和shell中变量$符含义不同;文件的每一行称为记录;省略action,则默认执行print $0 的操作。

 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, ...
  要点:
  1、逗号分隔符;
  2、输出的各item可以是字符串,也可以是数值、当前记录的字段、变量或awk的表达式;
  3、如省略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变量:内置和自定义变量
  内置变量
  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选项定义变量
  -v var=value
  awk -v test='hello gawk' '{print test}' /etc/fstab
  awk -v test='hello gawk' 'begin{print test}'
  在program直接定义变量
  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:root:/root:/bin/bash###bin:x:1:1:bin:/bin:/sbin/nologin###daemon:x:2:2:daemon:/sbin:/sbin/nologin###......

[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
# 如果后面跟多个文件的话,要想显示每个文件的行数,变量为fnr,如果不加f,则行号累加
1
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

自定义变量演示:
#通过过-v选项定义变量
[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,...
  1、必须指定format
  2、不会自动换行,需要显式给出换行控制符\n;
  3、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所在的位置,以字符串的形式显示;默认不自动换行;
rootbindaemonadmlpsyncshutdownhalt...

[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

操作符:
  1、算数操作符:
  x+y, x-y, x*y, x/y, x^y(x的y次方), x%y
  -x 转换为负数;
  +x 转换为数值;
  2、赋值操作符:
  =, +=, -=, *=, /=, %=, ^=, ++, --
  3、比较操作符:
  >, >=, <, <=, !=, ==
  4、模式匹配符:
  ~ 左边是否和右边匹配包含
  !~ 是否不匹配
  示例:
  cat /etc/passwd |awk '$0 ~ /root/' |wc -l
  cat /etc/passwd |awk '$0 !~ /root/' |wc -l
  5、逻辑操作符:
  &&,||,!
  示例:
  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
  6、函数调用:
  function_name(argu1, argu2, ...)
 7、条件表达式:
  selector?if-true-expression:if-false-expression
演示:
# 显示用户的uid如果大等于1000则为普通用户,否则为管理员或系统用户,并定义格式输出
[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
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 sysuser
systemd-bus-proxy:sysadmin or sysuser
systemd-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:
  pattern:根据pattern条件,过滤出匹配的行,再对这些行做处理

  1、如果未指定pattern:空模式则逐行匹配每一行
  2、/regular expression/:仅处理能够被模式匹配到的行,需要用/ /括起来(正则表达式过滤);
  示例:
  awk '/^uuid/{print $1}' /etc/fstab
  awk '!/^uuid/{print $1}' /etc/fstab
  3、relational expression: 关系表达式过滤;条件为"真"会被过滤出来
  真:结果为非0值、非空字符串、条件成立
  假:结果为0、空字符串、条件不成立
 示例:
  awk -f: '$3>=1000{print $1,$3}' /etc/passwd
  4、line ranges:行范围定界(通过两个模式匹配定界)
  start_pat,end_pat:/pat1/,/pat2/不支持直接给出数字格式
  示例:
  awk -f: '/^root/,/^nobody/{print $1}' /etc/passwd
  awk -f: '(nr>=2&&nr<=10){print $1}' /etc/passwd
  5、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
#
#
#
#
#
#
#
# 关系表达式,也可以称为比较表达式,条件为真,才会被处理。如果uid大于等于1000,则打印用户名和uid
[root@centos7 ~]# awk -f: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534
tao 1000

# 表示最后一个字段等于/bin/bash,则打印用户名和uid
[root@centos7 ~]# awk -f: '$nf=="/bin/bash"{print $1,$3}' /etc/passwd
root 0
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/模式匹配到的行开始,到第一次被/^nobody/模式匹配到的行结束
[root@centos7 ~]# awk -f: '/^root/,/^nobody/{print $1}' /etc/passwd
root
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/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 0
bin 1
daemon 2
adm 3
lp 4
sync 5
dbus 81
polkitd 997
abrt 173
colord 996
tcpdump 72
tao 1000
=======================
end

awk控制语句:if-else
  语法:
  if(condition) statement [else statement]
  使用场景:对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
# 如果字段大于5,就打印
[root@centos7 ~]# awk '{if(nf>5) print $0}' /etc/fstab
# 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
# 模式匹配,匹配以/dev开头的行,注意这里要对/ 转义,模式匹配一定要写在 “/ /”中
[root@centos7 ~]# df -h |awk -f[%] '/^\/dev/{print $1}' |awk '{print $1,$nf}'
/dev/sda2 3
/dev/sda3 14
/dev/sda1 29
# 如果利用率大于等于20,就打印第一字段
[root@centos7 ~]# df -h |awk -f[%] '/^\/dev/{print $1}' |awk '{if($nf>=20) print $1}'
/dev/sda1

awk控制语句:while循环
  语法:条件“真”,进入循环;条件“假”,退出循环
    while(condition) statement
  使用场景:
  1、对一行内的多个字段逐一做相同处理时使用
  2、对数组中的各元素逐一做相同处理时使用

演示:
# 取文件模式所匹配的行
[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.cfg
7
6

# 对每一行中各字段个数做统计。
这里用到了while循环,当i小于等于字段数量时就执行打印这一字段,及字段长短,并且执行i++,注意循环体用{}括起来
[root@centos7 ~]# awk '/[[:space:]]*linux16/{i=1;while(i<=nf) {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
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