• shell语法 05-Linux文本处理-awk


    • awk是一种编程语言
    • 适合文本处理和报表生成
    语法格式
    awk	[option] 'pattern{action}' file
    awk [参数]    '条件{动作}'       文件
    

    awk命令的参数选项

    • -F 指定字段分隔符
    • -v 定义或修改一个awk内部的变量

    awk命令的常见功能

    • 指定分隔符显示某几列
    # 直接取出显示出日志文件的url的这一列
    awk -F "GET|HTTP" '{print $2}' access.log
    
    • 通过正则表达式取出你想要的内容
    # 分析生产环境中的日志找出谁在破解用户密码
    awk '$6~/Failed/{print $11}' /var/log/secure
    
    • 显示出某个范围内的内容
    # 显示文件的20到30行
    awk 'NR==20,NR==30' filename
    
    • 通过awk进行统计计算
    # 计算总和
    awk '{sum+=$0}END{print sum}' test.txt
    
    • awk数组计算与去重
    # 对日志进行统计与计数
    awk '{array[$1]++}END{for(key in array)print key,array[key]}' access.log
    

    指定分隔符显示某几列

    # 输出passwd的每一行
    awk '{print $0}' /etc/passwd
    
    # 针对每行以‘:’为分割符,输出第一项
    awk -F":" '{ print $1 }' /etc/passwd
    
    # 针对每行以‘:’为分割符,输出第一项和第二项
    awk -F":" '{ print $1 $3 }' /etc/passwd
    
    # 针对每行以‘:’为分割符,输出第一项和第二项,并格式化输出
    awk -F":" '{ print $1 " " $3 }' /etc/passwd
    awk -F":" '{ print "username: " $1 "		uid:" $3 }' /etc/passwd
    

    BEGIN和END模块

    • 在 awk 开始处理输入文件中的文本之前,执行初始化代码(BEGIN内的代码块)。
    • awk 在处理了输入文件中的所有行之后执行END块。
    • END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。

    赋值运算符

    [root@yum tmp]# awk 'BEGIN{a=5;a+=5;print a}'
    10
    

    逻辑运算符

    [root@yum tmp]# awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'
    0 1
    

    正则运算符

    [root@yum tmp]# awk 'BEGIN{a="100testaaa";if(a~/100/){print "ok"}}'
    ok
    [root@yum tmp]# echo|awk 'BEGIN{a="100testaaa"}a~/100/{print "ok"}'
    ok
    

    关系运算符

    • 其 > < 可以作为字符串比较,也可以用作数值比较,
    • 关键看操作数如果是字符串,就会转换为字符串比较。
    • 两个都为数字 才转为数值比较。
    • 字符串比较:按照ascii码顺序比较。
    [root@yum tmp]# awk 'BEGIN{a=11;if(a>=9){print "ok"}}'
    ok
    [root@yum tmp]# awk 'BEGIN{a;if(a>=b){print "ok"}}'
    ok
    

    算术运算符

    • 所有用作算术运算符进行操作,操作数自动转为数值,
    • 所有非数值都变为0。
    [root@yum tmp]# awk 'BEGIN{a="b";print a++,++a}'
    0 2
    [root@yum tmp]# awk 'BEGIN{a="20b4";print a++,++a}'
    20 22
    

    其他运算符

    • ?:三目运算符
    [root@yum tmp]# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'
    ok
    [root@yum tmp]# awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'
    err
    

    awk内置变量

    变量名 属性
    $0 当前记录
    $1~$n 当前记录的第n个字段
    FS 输入字段分隔符,默认是空格
    RS 输入记录分隔符,默认为换行符
    NF 当前记录中的字段个数,就是有多少列
    NR 已经读出的记录数,就是行号,从1开始
    OFS 输出字段分割符,默认是空格
    ORS 输出记录分隔符,默认为换行符

    字段分隔符 FS

    • FS=" +" 一个或多个 Tab 分隔
    [root@yum tmp]# cat tab.txt
    ww		CC		IDD
    
    [root@yum tmp]# awk 'BEGIN{FS="	+"}{print $1,$2,$3}' tab.txt
    ww CC IDD
    
    
    • FS="[[:space:]+]" 一个或多个空白空格,默认的
    [root@yum tmp]# cat space.txt
    we are           studing awk now!
    [root@yum tmp]# awk -F [[:space:]+] '{print $1,$2}' space.txt
    we are
    
    • FS="[" ":]+" 以一个或多个空格或:分隔
    [root@yum tmp]# cat hello.txt
    root:x:0:0:root: /root:/bin/bash
    
    [root@yum tmp]# awk -F [" ":]+ '{print $1,$2,$3}' hello.txt
    root x 0
    

    字段数量 NF

    • 已":"为分隔符,分隔字段数量NF为8个则输出该行
    [root@yum tmp]# cat hello.txt
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin:888
    
    [root@yum tmp]# awk -F ":" 'NF==8{print $0}' hello.txt
    bin:x:1:1:bin:/bin:/sbin/nologin:888
    

    记录数量 NR

    • 以一个或多个空格或:分隔得出的结果取第二行
    [root@yum tmp]# ifconfig eth0| awk -F [" ":]+ 'NR==2{print $4}'
    192.168.10.10
    

    RS 记录分隔符变量

    • 将 FS 设置成" "告诉 awk 每个字段都占据一行。
    • 通过将 RS 设置成"",告诉 awk每个地址记录都由空白行分隔。
    [root@yum tmp]# cat recode.txt
    Jimmy the Weasel
    100 Pleasant Drive
    San Francisco, CA 12345
    #此处是空白行
    Big Tony
    200 Incognito Ave.
    Suburbia, WA 67890
    
    [root@yum tmp]# cat awk.txt
    #!/bin/awk
    BEGIN {
        FS="
    "
        RS=""
    }
    {
        print $1 ", " $2 ", " $3
    }
    
    [root@yum tmp]# awk -f awk.txt recode.txt
    Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
    Big Tony, 200 Incognito Ave., Suburbia, WA 67890
    

    OFS 输出字段分隔符

    [root@yum tmp]# cat hello.txt
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin:888
    
    [root@yum tmp]# awk 'BEGIN{FS=":"}{print $1","$2","$3}' hello.txt
    root,x,0
    bin,x,1
    
    [root@yum tmp]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2,$3}' hello.txt
    root#x#0
    bin#x#1
    

    ORS 输出记录分隔符

    [root@yum tmp]# cat recode.txt
    Jimmy the Weasel
    100 Pleasant Drive
    San Francisco, CA 12345
    
    Big Tony
    200 Incognito Ave.
    Suburbia, WA 67890
    
    [root@yum tmp]# cat awk.txt
    #!/bin/awk
    BEGIN {
        FS="
    "
        RS=""
        ORS="
    
    "
    } 
    {
        print $1 ", " $2 ", "$3
    }
    
    [root@yum tmp]# awk -f awk.txt recode.txt
    Jimmy the Weasel, 100 Pleasant Drive, San Francisco, CA 12345
    Big Tony, 200 Incognito Ave., Suburbia, WA 67890
    
    

    规则表达式

    • awk '/REG/{action} ' file
    • /REG/为正则表达式,
    • 可以将$0 中,满足条件的记录送入到:action 进行处理
    [root@yum tmp]# awk '/root/{print $0}' passwd
    root:x:0:0:root: /root:/bin/bash
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@yum tmp]# awk -F : '$5~/root/{print $0}' passwd
    root:x:0:0:root: /root:/bin/bash
    [root@yum tmp]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print $4}' #取出 ip
    192.168.10.10
    [root@yum tmp]# ifconfig eth0|awk 'BEGIN{FS="([[:space:]]|:)+"} NR==2{print $4}' #取出 ip
    192.168.10.10
    

    布尔表达式

    • awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。
    [root@yum tmp]# awk -F: '$1=="root"{print $0}' passwd
    root:x:0:0:root: /root:/bin/bash
    [root@yum tmp]# awk -F: '($1=="root")&&($5=="root"){print $0}' passwd
    root:x:0:0:root: /root:/bin/bash
    

    条件语句

    {
        if ( $1== "foo" ) {
            if ( $2== "foo" ) {
                print "uno"
            } else {
                print "one"
            }
        } elseif ($1== "bar" ) {
            print "two"
        } else {
            print "three"
        }
    }
    

    循环结构

    do...while循环
    {
        count=1
        do {
            print "I get printed at least once no matter what"
        } while ( count !=1 )
    }
    
    for 循环
    {
        for ( x=1;x<=4;x++ ) {
            print "iteration", x
        }
    }
    

    break和continue

    {
        x=1
        while (1) {
            if ( x==4 ) {
                x++
                continue
            }
            print "iteration", x
            if ( x>20 ) {
                break
            }
        x++
    }
    

    数组

    {
        cities[1]=”beijing”
        cities[2]=”shanghai”
        cities[“three”]=”guangzhou”
        for( c in cities) {
            print cities[c]
        }
        print cities[1]
        print cities[“1”]
        print cities[“three”]
    }
    

    例子

    查看服务器连接状态并汇总
    netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}'
    
    统计 web 日志访问流量
    要求输出访问次数
    请求页面或图片
    每个请求的总大小
    总访问流量的大小汇总
    
    awk '{a[$7]+=$10;++b[$7];total+=$10}END{for(x in a)print b[x],x,a[x]|"sort -rn -k1";print
    "total size is :"total}' access_log
    
    a[$7]+=$10表示以第7列为下标的数组($10列为$7列的大小)
    把他们大小累加得到$7每次访问的大小
    后面的for循环有个取巧的地方,a和b数组的下标相同
    所以一条for语句足矣
    

    awk常用函数

    函数 说明
    gsub( Ere, Repl, [ In ] ) 除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行。
    sub( Ere, Repl, [ In ] ) 用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere参数指定的扩展正则表达式的第一个具体值。 sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与 Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录( $0 记录变量)。
    index( String1, String2 ) 在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从 1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零)。
    length [(String)] 返回 String 参数指定的字符串的长度(字符形式)。如果未给出String 参数,则返回整个记录的长度( $0 记录变量)。
    blength [(String)] 返回 String 参数指定的字符串的长度(以字节为单位)。如果未给出String 参数,则返回整个记录的长度( $0 记录变量)。
    substr( String, M, [ N ] ) 返回具有 N 参数指定的字符数量子串。子串从 String 参数指定的字符串取得,其字符以 M 参数指定的位置开始。 M 参数指定为将String 参数中的第一个字符作为编号 1。如果未指定 N 参数,则子串的长度将是 M 参数指定的位置到 String 参数的末尾 的长度。
    match( String, Ere ) 在 String 参数指定的字符串( Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从 1 开始编号,或如果 Ere 参数不出现,则返回 0 (零)。 RSTART 特殊变量设置为返回值。 RLENGTH特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一)。
    split( String, A, [Ere] ) 将 String 参数指定的参数分割为数组元素 A[1], A[2], . . ., A[n],并返回 n 变量的值。此分隔可以通过 Ere 参数指定的扩展正则表达式进行,或用当前字段分隔符( FS 特殊变量)来进行(如果没有给出 Ere参数)。除非上下文指明特定的元素还应具有一个数字值,否则 A 数组中的元素用字符串值来创建。
    tolower( String ) 返回 String 参数指定的字符串,字符串中每个大写字符将更改为小写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。
    toupper( String ) 返回 String 参数指定的字符串,字符串中每个小写字符将更改为大写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。
    sprintf(Format, Expr,Expr, . . . ) 根据 Format 参数指定的 printf 子例程格式字符串来格式化 Expr参数指定的表达式并返回最后生成的字符串。

    替换

    awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}' this is a test!test!
    在info中查找满足正则表达式,/[0-9]+/用”!”替换,并且替换后的值,赋值给 info未给info值,默认是$0
    

    查找

    awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok 
    #未找到,返回 0
    

    匹配查找

    awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'ok 
    #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到
    

    截取

    awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'s is a tes 
    #从第 4 个 字符开始,截取 10 个长度字符串
    

    分割

    awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 44 test 1 this 2 is 3 a
    #分割info,动态创建数组tA,awk for …in 循环,是一个无序的循环。并不是从数组下标1…n 开始
    
  • 相关阅读:
    python之----------字符编码具体原理
    css部分复习整理
    秘钥登录服务器执行shell脚本
    idea配置github
    InteliJ IDEA 简单使用:配置项目所需jdk
    IntelliJ IDEA 中安装junit插件
    IDEA 运行maven命令时报错: -Dmaven.multiModuleProjectDirectory system propery is not set
    idea如何编译maven项目
    idea项目左边栏只能看到文件看不到项目结构
    idea如何导入一个maven项目
  • 原文地址:https://www.cnblogs.com/liangjingfu/p/9419412.html
Copyright © 2020-2023  润新知