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

    AKW: Aho,Weinberger,Kernighan  这个工具的三个人的作者
            1970s出现的-->New AWK ,NAWK

    
    linux上用的是GNU awk 简称为gawk
    
gwak -pattern scanning and processing language

处理:一次读取一行文本,根据指明的输入分隔符切割为n个组成部分;内
建变量$1...$n   显示整行片段为$0

基本用法:gawk  [options]  'program'  FILE1 [FILE...n]

    program:  PATTREN{ACTION STATEMENTs}

        语句之间用;分隔

选项 
 -F ""指明字段分隔符
 -v  var=value :自定义变量
 

1、print 
  

    print item1,item2,...
例如  awk '{print $1,$2}'  以默认空格为分割字段显示$1  $2
不写,的话会连接显示 $1$2
(1)都号分隔符
(2)输出的item可以是字符串,数值,当前记录的子段、变量或awk表达式
字符串连接时  '{print "hello:" $1}' 加入字符  ""里面的东西不会改变,
因此$1不能在""里面
(3)省略item,就相当于print $0  打印整行

2、变量
  1 内建变量
    FS:input  filed seperator,默认为空白字符
    OFS:output filed seperator,默认为空白字符
    RS: 输入时的换行符
    ORS:输出时的换行符    
    NF:显示行的字段数
这个时候如果打印$NF 是打印每行字段的最后一个字段
因为你统计了每行的字段
{print NF}  {print NR}
因此打印变量不要加$

    NR:统计文件的行数
    FNR:每个文件单独计数行数  {print FNR}  file1 file2 ..
    FILENAME:当前正在处理的文件名  
如果直接打印,是每处理一行就会显示一次文件名
可以用 'BEGIN{print FILENAME}' 显示一次

    ARGC:命令行参数的个数
    ARGV:数组,保存的是命令行中所给定的各参数
例如  awk 'BEGIN{print ARGV[0] ARGV[1] ARGV[2] ARGC}' file1 file2
就会显示  awk  file1  file2  3  三个参数和总计的参数量

例如
eg1: awk -v FS=':' '{print $1}'  /etc/passwd
     等于awk -F: '{print $1}'  /etc/passwd

eg2:定义输出分隔符
  awk -v FS=':' -v OFS=':'  '{print $1}'  /etc/passwd
输出也打印为分割符为:

eg3  -v RS=' '  把空白字符全部当做换行符
    -v ORS='#'  #作为输出的换行

 2 自定义变量
    -v  var=value
    变量名区分大小写、引用变量不需要$

如果不对文件做处理,必须'BEGIN{}'  而不是在处理文件过程中,就不用加文件名称了

 3printf 命令

 格式化输出:printf FORMAT, item1 ....

    (1)FORMAT必须给出
    (2)printf不会自动换行,需要显式给出\n
    (3)FORMAT中需要分别为后面的每个item指定一个格式化符号
    格式符
    %c 显式字符的ASCII码
    %d,%i 显式为十进制,整数
    %e,%E 显式为科学计数法
    %f 显式为浮点数
    %g,%G以科学计数法,浮点形式显式数值
    %s显式字符串
    %u 无符号整数
    %% 显式% 本身

例如 awk -F: '{printf "Username: $s\n",$1}'  /etc/passwd
类似C语言版的输出

awk -F: '{printf "Username: $s, UID:%d\n",$1,$3}'  /etc/passwd

    修饰符
    #[.#]: 第一个#控制显示的宽度,第二个#控制小数的精度可以不加
        %3.1f

awk -F: '{printf "Username: $15s, UID:%8d\n",$1,$3}'  /etc/passwd

默认为右对齐显示   
    -为左对齐
awk -F: '{printf "Username: $-15s, UID:%8d\n",$1,$3}'  /etc/passwd
        %-15s 左对齐
    -左对齐
    +显示数值的符号

 4操作符

   算数操作符:
    x-+\*^%
    -x 负值
    +x 转换为数值

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

   赋值操作符
    =,+=,-=,*=,%=,^=,\=
    ++,--

   比较操作符
    < > >=  <= == != 

   模式匹配符
    
    ~  是否匹配   
    !~是否不匹配

   逻辑操作符
    && ||  
    !
   函数调用
    function_name(argu1,argu2, ...)

   条件表达式
    selector?if-true-expression:if-false-expression
    1?2:3
    1对执行2,不对执行3
    
   eg:  awk -F: '{$3>=1000?usertype="common":usertype="sys";printf
 "%15s:%-s\n",$1,usertype}'  /etc/passwd

 5 PATTERN

   (1) empty:空模式,匹配每一行
   (2)/regular expression/  :仅处理能被此处模式匹配到的行(过滤)
eg1:  awk '/^UUID/{print $1}'  /etc/fstab
仅显示开头为UUID 的行
 awk '!/^UUID/{print $1}'  /etc/fstab
加!对整个过滤模式取反

正则表达式

   (3)relational expression:关系表达式:如果有“真”有“假”;结果为真才被处理
    真:结果为非0值,非空字符串
eg: awk -F: '$3>=1000{prinf $1,$3}' /etc/passwd

awk -F: '$NF=="/bin/bash"{print $1,$NF}'  /etc/passwd
打印最后一个字段为/bin/bash的行

   (4)line ranges:行范围,
    startline,endline (地址定界) /pat1/ /pat2/
    
    注意:不支持直接给出数字的格式
    awk -F: '(NR>=2&&NR<=10){print $1}'  /etc/passwd
   (5)BEGIN/END模式
    BEGIN{} 在开始处理文件中的文本之前执行一次
    END{}在文本处理完成之后执行一次
    

6常用的action

 (1)表达式Expressions
 (2)控制语句
 (3)组合语句
 (4)输入语句
 (5)输出语句

7控制语句
  
  if(confition) {statements}
  if(confition) {statements} else {statements}
    ...
    ...

 7.1  if-else
   语法: if(conditon) statement [else statement]

   awk -F: '{if($3>=1000) print $1,$3}'  /etc/passwd

   awk -F: '{if($3>=1000) {print $1,$3} else {print $1,$3}}'  /etc/passwd

   df -h|awk -F[%]  '{print $5}' |awk '{print $NF}'
   显示最后一个字段

    
   df -h|awk -F[%]  '/^\/dev/{print $5}' |awk '{print $NF}'
   \/转义    以/dev开头的行

   7.2while循环
      语法:while(conditon)  statement
    条件“真”,进入循环;条件“假”,退出循环

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

    awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++}}'  /etc/grub2.cfg
         统计字段

    
    awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7){print $i,length($i)};i++}}'  /etc/grub2.cfg
         统计字段
    

  7.3 do-while循环
    do statement  while(condition)
    至少执行一次循环体

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

    for(variable assignment;condition;iteration process)  {for-body}

    
  7.5 switch语句
     语法:switch(expression)

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

  7.6 break  continue
    break [n]
    continue
  7.7next
    提前结束对本行的处理而直接进入下一行

  awk -F: '{if($3%2!=0) next; print $1,$3}'  /etc/passwd

 8array
    关联数组array[index-expression]

    index-expression
    (1)可使用任意字符串
    (2)如果某数组元素事先不存在,在引用时awk会自动创建此元素,并且初始化为
“空串”
    

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

    weekdays["mon"]="Monday"  引用元素不要加$
    要使用双引号

eg:  awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]=Tuesday;print weekdays["mon"]}'

    遍历数组中每个元素
    for(var in array) {for-body}

    var会遍历array的每个索引

netstat -tan |awk '/^tcp\>/{state[$NF]++}END{for(i in state) {print i,state[i]}}'

其中  state[$NF]++表示 索引数组的自增
结果为  
Listen  3
Establish  3
用于统计服务很给力

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之间一个随机数

    字符串处理
    length([s])  返回指定字符串的长度
    sub(r,s,[t])  r表示模式来查找t所表示的字符串中的匹配的内容,并将其第一次出现替换为s
    gsub(r,s,[t])  全局替换
    
    split(s,a,[r]) 以r为分隔符切割字符s,并将切割后的结果保存至a所表示的数组中。数组从1标号
例如  netstat -tan |awk '/^tcp\>/{split($5,ip,":");print ip[1]}'   打印每一行的ip    

netstat -tan |
awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
统计ip次数

  9.2自定义函数