前言

一、木石前盟

  众所周知,我们大中华上下5千年历史,其中当属“四大名著”最让人津津乐道。《红楼梦》一书更为四大名著之首,被评为中国古典章回小说的巅峰之作,是中国最受重视的一部文学作品。此书由清代作家曹雪芹所作,故事主线为贾宝玉、林黛玉及薛宝钗三人的爱情与婚姻悲剧,以及贾府等四大家族的没落。

  故事开头即提到木石前盟一事。说到林黛玉的前身是绛珠仙草,贾宝玉的前身是神瑛侍者。《红楼梦》第一回“甄士隐梦幻识通灵 贾雨村风尘怀闺秀 ”中有这样一段描写:

  西方灵河岸上三生石畔,有绛珠草一株,时有赤瑕宫神瑛侍者,日以甘露灌溉,这绛珠草始得久延岁月。后来既受天地精华,复得雨露滋养,遂得脱却草胎木质,得换人形,仅修成个女体,终日游于离恨天外。饥则食蜜青果为膳,渴则饮灌愁海水为汤。只因尚未酬报灌溉之德,故其五内便郁结着一段缠绵不尽之意。恰这神瑛侍者凡心偶炽,乘此昌明太平朝世,意欲下凡造历幻缘,已在警幻仙子案前挂了号。警幻亦曾问及,灌溉之情未偿,趁此倒可了结的。那绛珠仙子道:“他是甘露之惠,我并无此水可还。他既下世为人,我也去下世为人,但把我一生所有的眼泪还他,也偿还得过他了。”


而今天我们要讲的可不是贾宝玉和林黛玉之间的情愫姻缘,我们今天的主角是awk,一种优良的文本处理工具,而且它还有另外一个名字:gawk。

GNU awk:

  • 文本处理三工具:grep, sed, awk 
    grep, egrep, fgrep:文本过滤工具;pattern 
    sed: 行编辑器 
    模式空间、保持空间 
    awk(实际上是编程语言的解释器,也可以说是一个编程语言):报告生成器,格式化文本输出;

    AWK: Aho, Weinberger, Kernighan --> New AWK, NAWK
    
            GNU awk(awk 是gawk的链接文件), gawk (也是一次读取一行文本,跟sed一样)


  • gawk - pattern scanning and processing language (模式扫描及实现处理语言)

    • 基本用法:gawk [options] 'program' FILE …

program: PATTERN{ACTION STATEMENTS(语句)}
     PATTERN:模式有多种,有地址定界作用,不同于sed或grep里面的概念;
ACTION STATEMENTS:动作语句,可有多个语句,但语句之间用分号分隔;
      可认为是脚本里的调用命令,这不过用的是awk内建命令;如:
        print, printf   (主要功能:实现文本格式化输出)

    • 选项:

-F:指明输入时用到的字段分隔符;
-v var=value: 自定义变量


  • 1、print

    print item1, item2, ...
          默认输出分隔符是空白字符;
    • 要点: 
      (1) 逗号分隔符; 
      (2) 输出的各item可以是字符串,也可以是数值;当前记录的字段、变量($1,$2,..)或awk的表达式;  
      (3) 如省略item,相当于print $0($0代表一整行内容,默认显示打印整行内容);

Linux 文本三剑客之awk 木石前盟_第1张图片

]# tail -5 /etc/fstab |awk '{print "hello:$1"}'
      放在引号里变量不会做替换;
显示内容:
      hello:$1      
      hello:$1      
      hello:$1      
      hello:$1
      hello:$1
      
      
-------------------------------------------------------------------------------

]# tail -5 /etc/fstab |awk '{print "hello:"$1}'
显示内容:
      hello:#      
      hello:UUID=7db66111-7836-4dd8-8b10-d26b45faebb9      
      hello:UUID=f004f1af-6d47-4b6b-94d8-95fb2d58ae42      
      hello:UUID=c396e749-0a90-4b07-92ad-18627d4f8f4e      
      hello:UUID=f4999e79-e3f1-45ed-bcb3-90493dadc48f
注意:在awk中,变量做替换是不用引号的;


--------------------------------------------------------------------------------
]# tail -5 /etc/fstab |awk '{print " "}'
显示空白字符,如果每一行都有空白,那就每一行都显示空白;


  • 2、变量

    FS:input field seperator(输入时字段的分隔符),默认为空白字符; 
    OFS:output field seperator(输出时字段的分隔符),默认为空白字符; 
    RS:input record seperator,输入时的换行符;一行为一条record;默认为行分隔符; 
    ORS:output record seperator,输出时的换行符;一行为一条record;默认为行分隔符;

    • 2.1 内建变量

  • 例如:

]# awk '{print $1}' /etc/passwd
    默认以空白符为分隔符,显示第1字段;
显示部分内容:    aaa6:x:1017:1017::/home/aaa6:/bin/bash    aaa7:x:1018:1018::/home/aaa7:/bin/bash    aaa8:x:1019:1019::/home/aaa8:/bin/bash    aaa9:x:1020:1020::/home/aaa9:/bin/bash    aaa10:x:1021:1021::/home/aaa10:/bin/bash-------------------------------------------------------------------------------]# awk -v FS=':' '{print $1}' /etc/passwd    以冒号为分隔符,显示第1字段;以默认空格为分隔符输出;显示部分内容:    aaa6    aaa7    aaa8    aaa9    aaa10-------------------------------------------------------------------------------]# awk -F:'{print $1}' /etc/passwd    以冒号为分隔符,显示第1字段;以默认空格为分隔符输出;显示部分内容:    aaa6    aaa7    aaa8    aaa9    aaa10

]# awk -v RS=' ' '{print $0}' /etc/passwd     以空白字符为输入换行符;$0为显示整行内容,为默认显示可省略;输出时,把已有输出换行符,在加上定义的空白字符为输入换行符都当做了输出换行符;

]# awk -v RS=' ' -v ORS='#' '{print}' /etc/passwd     以空格为输入换行符,以#为输出换行符;则输出时把每行空格替换成了#,比较诡异;

数值统计的内建变量:在awk中引用变量不加符号;1,$2,..是字段的固定使用的变量除外;

NF:number of field,字段数量,即每行的字段数量; 
注意:{print NF}, {print $NF} (加$ 即显示最后的字段) 

  • 例如:

]# awk '{print NF}' /etc/fstab    显示fstab文件中每一行有多少字段;]# awk '{print $NF}' /etc/fstab    表示为显示每行最后一个字段;]# awk '{print NR}' /etc/fstab    统计行数,显示行号;

NR:number of record, 行数;即对文件中的行进行编号; 
FNR:各文件分别计数;行数;

  • 例如:

]# awk '{print NR}' /etc/fstab /etc/issue    显示内容:两文件的总行数;]# awk '{print FNR}' /etc/fstab /etc/issue    显示内容:两文件分别显示行数;

FILENAME:当前文件名;处理一行显示一次;

  • 例如:

]# awk '{print FILENAME}' /etc/fstab    显示内容:每行的文件名;

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

  • 例如:

]# awk '{print ARGC}' /etc/fstab:显示文件的每一行在命令行中参数的个数;    显示内容:即每一行执行命令时,都有2个参数,即awk和/etc/fstab;---------------------------------------------------------------------------------------------]# awk 'BEGIN{print ARGC}' /etc/fstab:仅显示一次在命令行中参数的个数;    显示内容:2;---------------------------------------------------------------------------------------------]# awk 'BEGIN{print ARGV}' /etc/fstab:显示数组,命令行中所给定的各参数,即显示数组中各元素;    显示内容:awk: cmd. line:1: fatal: attempt to use array `ARGV' in a scalar context--------------------------------------------------------------------------------------------]# awk 'BEGIN{print ARGV[0]}' /etc/fstab:显示命令行中所给定的各参数的数组中第1个元素;    显示内容:awk;--------------------------------------------------------------------------------------------]# awk 'BEGIN{print ARGV[1]}' /etc/fstab:显示命令行中所给定的各参数的数组中第2个元素;

  • 2.2 自定义变量

    • (1) -v var=value 
      变量名区分字符大小写;

    • (2) 在program中直接定义

注意:定义变量,同bash中一样,用时定义即可;

  • 例如:

]# awk -v test='hello gawk' '{print test}' /etc/fstab:文件此处没什么用,只有一个显示行数作用;即文件有12行    显示了每行显示一次,显示了12行;-------------------------------------------------------------------------------------------]# awk -v test='hello gawk' 'BEGIN{print test}':定义test变量并赋值为hello gawk,且显示一次test变量的内容;------------------------------------------------------------------------------------------]# awk 'BEGIN{test="hello gawk";print test}':直接在程序中定义变量(赋值语句),多个语句之间使用分号分隔,表示意义同上;

  • 3、printf命令

    • 格式化输出:printf FORMAT, item1, item2, …

FORMAT是格式符,为每个item按位占一个位留一个特殊符号,所以item最终会显示在format指定格式符号的位置上;

  • 要点:

    • (1) FORMAT必须给出;

    • (2) 不会自动换行,需要显示给出换行控制符,\n;

    • (3) FORMAT中需要分别为后面的每个item指定一个格式化符号;

  • 格式符:


    • 例如:

  1. %c: 显示字符的ASCII码;

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

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

  4. %f:显示为浮点数;

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

  6. %s:显示字符串;

  7. %u:无符号整数;

  8. %%: 显示%自身;

]# awk -F: '{printf "%s",$1}' /etc/passwd:以字符串显示每行的第1字段;显示内容:rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodyavahiautoipddbuspolkitdabrtcolordlibstoragemgmtrpcrtkitusbmuxdchroymysqltssntppulsegdmrpcusernfsnobodypostfixsshdtcpdumplsjtestuser1centosubuntuubuntomagedusparkmageeduaaabbbcccapacheaaa1aaa2aaa3aaa4aaa5aaa6aaa7aaa8aaa9aaa10--------------------------------------------------------------------------------------------]# awk -F: '{printf "%s\n",$1}' /etc/passwd::以字符串显示每行的第1字段;每字段一行;    显示部分内容:aaa6aaa7aaa8aaa9aaa10--------------------------------------------------------------------------------------------]# awk -F: '{printf "username:%s\n",$1}' /etc/passwd:显示指定字符串即username:,同时以字符串显示每行的第1字段;每字段一行;--------------------------------------------------------------------------------------------]# awk -F: '{printf "username:%s, UID:%d\n",$1,$3}' /etc/passwd    显示部分内容:username:aaa6, UID:1017username:aaa7, UID:1018username:aaa8, UID:1019username:aaa9, UID:1020username:aaa10, UID:1021

  • 修饰符:


    • 例如:

  1. #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度;默认右对齐;

  2.    %3.1f3表示显示3个字符的宽度;

  3. -: 左对齐

  4. +:显示数值的符号     bash也支持printf语句)

]# awk -F: '{printf "username:%15s,UID:%d\n",$1,$3}' /etc/passwd:设定username:为15个字符宽度,默认右对齐;    显示部分内容:username: aaa6,UID:1017username: aaa7,UID:1018username: aaa8,UID:1019username: aaa9,UID:1020username: aaa10,UID:1021---------------------------------------------------------------------------------------------]# awk -F: '{printf "username:%-15s,UID:%d\n",$1,$3}' /etc/passwd:同上但是为左对齐;--------------------------------------------------------------------------------------------]# awk -F: '{printf "username:%-15s,UID:%+d\n",$1,$3}' /etc/passwd:显示第2字段正负号;    显示部分内容:username:aaa6 ,UID:+1017username:aaa7 ,UID:+1018username:aaa8 ,UID:+1019username:aaa9 ,UID:+1020username:aaa10 ,UID:+1021

  • 4、操作符

    • 算术操作符:


    • 字符串操作符:没有符号的操作符,字符串连接(一般使用内建函数进行字符串切片)

    • 赋值操作符:


    • 比较操作符:


    • 模式匹配符:


    • 逻辑操作符:


    • 函数调用:


    • 条件表达式:


  1. selector?if-true-expression:if-false-expression  (正确执行第一个expr,错误执行第二个expr          //:selector(条件表达式)

  1. function_name(argu1, argu2, ...)  (规范的调用使用方式)

  1. &&

  2. ||

  3. !

  1. ~:是否匹配

  2. !~:是否不匹配

  1. >, >=, <, <=, !=, ==(等值比较)

  1. =, +=, -=, *=, /=, %=, ^=(增强相赋值)

  2. ++, --(自增、自减运算)

  1. x+y, x-y, x*y, x/y, x^y, x%y

  2. -x  (把正数转换为负数)

  3. +x: 转换为数值;

例子:判断一个用户类型,id大于1000则是普通用户(Common User),小于则是系统用户(Sysadmin or SysUser)。

# awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd【判断用户id是否>=1000,是在定义变量usertype为Common User,否则定义变量usertype为Sysadmin or SysUser,显示第1字段为15个字符宽度,usertype为左对齐;】

  • 5、PATTERN (能实现地址定界功能) 
    (1) empty:空模式,匹配每一行;** 
    (2) /regular expression/:仅处理能够被此处的(正则表达式)模式匹配到的行;前面加!表示对模式过滤的条件取反;**

~]# awk '/^UUID/{print $1}' /etc/fstab:显示UUID开头的行的第1字段;

(3) relational expression: 关系(比较)表达式;结果有“真”有“假”;结果为“真”才会被处理; 
真(两种):1.结果为非0值,2.非空字符串; 
假:0,空字符串;

]# awk '!/^UUID/{print $1}' /etc/fstab:表示取反,显示UUID开头的以外的行的第1字段;-------------------------------------------------------------------------------------------]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd:以冒号为分隔符,id号大于1000的用户,显示第1,3字段;-------------------------------------------------------------------------------------------]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd:显示默认为shell类型为bash的用户;-------------------------------------------------------------------------------------------]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd:功能同上;显示以bash结尾的用户,第1和最后一个字段;-------------------------------------------------------------------------------------------]# awk -F: '/^root/,/^mysql/{print $1}' /etc/passwd:从以root开头的行开始,到以mysql开头的行结束的行,显示第1字段;--------------------------------------------------------------------------------------------]# awk -F: 'NR>=2&&NR<=10{print $1}' /etc/passwd:显示从第2行到第10行的第1字段;

(4) line ranges:行范围, 
startline,endline:/pat1/,/pat2/ (第一次由模式匹配的行开始到第一次由模式到匹配的行结束)

注意: 不支持直接给出数字的格式

~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd   显示从第2行到第10行的第1字段;

(5) BEGIN/END模式

  • BEGIN{program}: 仅在开始处理文件中的文本之前执行一次;显示表头

  • END{program}:仅在文本处理完成之后命令结束之前执行一次;

]# awk -F: 'BEGIN{print " username uid \n--------------"}{print $1,$3}' /etc/passwd:显示表头;--------------------------------------------------------------------------------------------]# awk -F: '{print "username uid \n--------------";print $1,$3}' /etc/passwd显示部分内容:即每行都显示一遍;主程序执行前显示;--------------------------------------------------------------------------------------------]# awk -F: 'BEGIN{print " username uid \n--------------"}{print $1,$3}END{print "==========\n end"}' /etc/passwd:设置尾部显示;主程序结束后显示;

  • 6、常用的action

    • (1) Expressions (表达式)

    • (2) Control statements(控制语句):if, while等;

    • (3) Compound statements:组合语句; —-把多个语句放在代码块的语句

    • (4) input statements (输入语句)

    • (5) output statements

  • 7、控制语句

    if(condition) {statments}                  condition  (条件)    if(condition) {statments} else {statements}    (这即组合语句)    while(conditon) {statments}    do {statements} while(condition)    for(expr1;expr2;expr3) {statements}    break    continue    delete array[index]   (从数组中删除指定的元素)    delete array   ( 删除整个数组)    exit     { statements }        (多个语句写成代码组合在一块形成组合语句时,需要用{}括起来)
  • 7.1 if-else语句,支持双分支if语句,完成条件判断;

语法格式:if(condition) statement [else statement]   (一个语句不用加括号,双分支else语句 true和else后面都要加{})

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

  • 例如:

~]# awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd  (表示用 :做分隔符)以冒号为分隔符,判断用户ID>=1000,显示第1,3字段;(在centos 7)-----------------------------------------------------------------------------------------~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd以冒号为分隔符,判断ID>=1000的用户ID为普通用户;

~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd (以冒号为分隔符,判断默认shell为bash的用户,有哪些;)---------------------------------------------------------------------------------------------~]# awk '{if(NF>5) print $0}' /etc/fstab    (以默认空格为分隔符,判断某行的字段数是否大于5个才显示,$0可省略,默认显示整行)---------------------------------------------------------------------------------------------~]# df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}'    以%为分隔符,/dev开头的行取第1字段,再判断最后一个字段内容是否>=20;即判断磁盘使用超过20%的分区;

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

  • 7.2 while循环 
    语法:while(condition) statement

条件“真”,进入循环;条件“假”,退出循环;语句如果有多个,需要用{}括起来; (注意:第一为假时则不进入循环 )

使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用; 
例如:

~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg    【以空格开头0次或多次,后跟linux16的行,以空格为分隔符,显示每行中各字段的长度;】

~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)}; i++}}' /etc/grub2.cfg   【以空格开头0次或多次,后跟linux16的行,以空格为分隔符,只显示每行中字段的长度>=7字段;】

  • 7.3 do-while循环 (不常用) 
    语法:do statement while(condition) 
    意义:无论条件真假,至少执行一次循环体

  • 7.4 for循环 
    语法:for(expr1;expr2;expr3) statement

expr1:控制变量初始化;expr2:条件判断;expr3:控制变量的数值修正表达式;
for(variable assignment;condition;iteration process) {for-body}      //:variable assignment【变量赋值】;condition【条件判断表达式】;iteration process【变量修正表达式】;for-body【循环体语句】
~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg    【以空格开头0次或多次,后跟linux16的行,以空格为分隔符,显示每行中各字段的长度;同上while语句;】]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {if(length($i)>=7) {print $i,length($i)}}}' /etc/grub2.cfg    【以空格开头0次或多次,后跟linux16的行,以空格为分隔符,只显示每行中字段的长度>=7的字段;同上while语句;】

  • for循环特殊用法: 
    能够遍历数组中的元素

  • 语法:for(var in array) {for-body} //var in array:var【自定义的变量】in【关键字】 array【数组名】

  • 7.5 switch语句(在awk中用的不多) 
    语法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; …; default: statement} 
    即:switch(表达式) {case 值1或/正则式1/: 语句1; case 值1或/正则式1/: 语句2; …; default: 语句n} 
    判断表达式的值符合case里面的哪个条件,可以等于case里的值,也可以是被case里的正则表达式匹配;如果符合条件就执行该case里的语句,不会往下判断了;类似case语句,只不过是关键字写法不同;

    // case:关键字 default:statement【默认分支】

  • 7.6 break和continue

break [n]continue

在awk中能实现2重循环,awk本身可对文件每行循环,使用循环语句是为了遍历一行中的每个字段,或数组中的每个元素;

  • 7.7 next 
    提前结束对本行的处理而直接进入下一行;(类似于continue,continue是用来控制行内字串间跳转的,next是控制awk的本身循环的)

  • 例子:显示用户的id号为偶数的用户

~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd    【显示用户ID号为偶数的行;即判断id号是否能被2整除,如果不等于0,直接结束本行,直接进行下一行;】

  • 8、array (数组) 
    关联数组:array[index-expression] // array[](数组名);index-expression(索引表达式)

    • (1) 可使用任意字符串;字符串要使用双引号;

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

    • index-expression:

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

  • 例如:

]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'    //注意:字符串要使用双引号;引用数组中的元素不需使用$符号;

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

for(var in array) {for-body}即for(变量名 in 数组名) {循环体}变量名中保存的是数组的索引,而不是数组中的元素;注意:不要使用$符号;
  • 例如:

~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'    【遍历数组中的每个元素;要使用for循环;显示的次序可能不太和想象的一样;】

  • 注意:对应的变量var会遍历array的每个索引; 
    某个数组元素不存在,直接引用后会被创建且为空,做数值操作时当做0使用; 
    使用数组统计每一类数值各自出现次数时非常有用;

  • 例如:

state["LISTEN"]++state["ESTABLISHED"]++  (先显示索引,再显示索引元素的值)~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}'    【显示tcp每个状态分别出现的次数;】

]# systemctl status httpd.service]# systemctl start httpd.service]# vim /var/www/html/index.html    编辑内容:Test page    使用网页浏览可见此内容;]# tail /var/log/httpd/access_log:查看服务器访问日志;可对每一个ip地址做统计;
  • 例如:统计每个ip地址访问服务器的次数;

~]# awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
  • 练习1:统计/etc/fstab文件中每个文件系统类型出现的次数;

~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
  • 练习2:统计指定文件中每个单词出现的次数;

~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab

9、函数

  • 9.1 内置函数

  • 数值处理:

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

  • 例如:

]# awk 'BEGIN{print rand()}':执行多次都是同样的随机数;
  • 字符串处理:

length([s]):返回指定字符串的长度;sub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其第一次出现替换为s所表示的内容;[t]表示可选的  字符串;gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现均替换为s所表示的内容;split(s,a[,r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;
  • 例如:

]# awk -F: '{print sub(o,O,$1)}' /etc/passwd   //把每行的第1字段中,第一次出现的小写o替换为大写O;注意:仅替换每行一次出现的;

gsub(r,s,[t]):以r表示的模式来查找t所表示的字符中的匹配的内容,并将其所有出现的内容均替换为s所表示的内容; 
split(s,a[,r]):以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中;数组元素从1开始编号;

  • 例如:

]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'    【显示来访的主机地址连接的次数;】]# ab -c 100 -n 1000 http://172.18.252.22/index.html

解法:① 
 
② 

  • 9.2 自定义函数

            《sed和awk》