zoukankan      html  css  js  c++  java
  • awk实例

    1、Nginx日志分析

    日志格式:'$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"'

    日志记录:27.189.231.39 - - [09/Apr/2016:17:21:23 +0800] "GET /Public/index/images/icon_pre.png HTTP/1.1" 200 44668 "http://www.test.com/Public/index/css/global.css" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36" "-"

    1)统计日志中访问最多的10个IP

    awk '{print $1}' nginx.log| sort | uniq -c | sort -rn | head -10 

    awk '{ip[$1]++}END{for (a in ip ) print ip[a],a}' nginx.log | sort -rn | head -10

    2)统计日志中访问大于100次的IP

    awk '{ip[$1]++}END{for(a in ip){if(ip[a]>100)print a}}' nginx.log

    3)统计2016年4月9日一天内访问最多的10个IP

    思路:先过滤出这个时间段的日志,然后去重,统计出现次数

    方法1:$ awk '$4>="[9/Apr/2016:00:00:01" && $4<="[9/Apr/2016:23:59:59" {a[$1]++}END{for(i in a)print a[i],i|"sort -k1 -nr|head -n10"}' access.log

    方法2:$ sed -n '/[9/Apr/2016:00:00:01/,/[9/Apr/2016:23:59:59/p' access.log |sort |uniq -c |sort -k1 -nr |head -n10  #前提开始时间与结束时间日志中必须存在

    4)统计当前时间前一分钟的访问数

    思路:先获取当前时间前一分钟对应日志格式的时间,再匹配统计

    $ date=$(date -d '-1 minute' +%d/%b/%Y:%H:%M);awk -vdate=$date '$0~date{c++}END{print c}' access.log

    $ date=$(date -d '-1 minute' +%d/%b/%Y:%H:%M);awk -vdate=$date '$4>="["date":00" && $4<="["date":59"{c++}END{print c}' access.log

    $ grep -c $(date -d '-1 minute' +%d/%b/%Y:%H:%M) access.log

    说明:date +%d/%b/%Y:%H:%M --> 09/Apr/2016:01:55

    5)统计访问最多的前10个页面($request)

    $ awk '{a[$7]++}END{for(i in a)print a[i],i|"sort -k1 -nr|head -n10"}' access.log

    6)统计每个URL访问内容的总大小($body_bytes_sent)

    $ awk '{a[$7]++;size[$7]+=$10}END{for(i in a)print a[i],size[i],i}' access.log

     

    7)统计每个IP访问状态码数量($status)

    $ awk '{a[$1" "$9]++}END{for(i in a)print i,a[i]}' access.log

    8)统计访问状态码为404的IP及出现次数

    $ awk '{if($9~/404/)a[$1" "$9]++}END{for(i in a)print i,a[i]}' access.log

    2、两个文件对比

    文件内容如下:

        $ cat a

        1

        2

        3

        4

        5

        6

        $ cat b

        3

        4

        5

        6

        7

        8

    1)找出相同记录

    方法1:$ awk 'FNR==NR{a[$0];next}($0 in a)' a b

            3

            4

            5

            6

            解释前,先看下FNR和NR区别:

            $ awk '{print NR,$0}' a b

            1 1

            2 2

            3 3

            4 4

            5 5

            6 6

            7 3

            8 4

            9 5

            10 6

            11 7

            12 8

            $ awk '{print FNR,$0}' a b

            1 1

            2 2

            3 3

            4 4

            5 5

            6 6

            1 3

            2 4

            3 5

            4 6

            5 7

            6 8

      

    可以看出NR是处理一行记录,编号就会加1,同时也可以看到awk将两个文件当成一个合并后的文件处理。

    而FNR则是处理一行记录,编号也会加1,但是,处理到第二个文件时,编号重新计数。

    说明:FNR和NR是内置变量。FNR==NR常用于对两个文件处理,这个例子可以理解为awk将两个文件当成一个文件处理。

    处理a文件时,FNR是等于NR的,条件为真,执行a[$0],next表达式,意思是将每条记录存放到a数组作为下标(无元素),next是跳出,类似于continue,不执行后面表达式。

    执行过程以此类推,直到处理b件时,FNR不等于NR(FNR重新计数是1,NR继续加1是7),条件为假,不执行后面a[$0],next表达式,直接执行($0 in a)表达式,这句意思是处理b文件第一条继续判断是否在a数组中,如果在则打印这条记录,以此类推。

    这样可能更好理解些:

    $ awk 'FNR==NR{a[$0]}NR>FNR{if($0 in a)print $0}' a b

    方法2:

     

    $ awk 'FNR==NR{a[$0]=1;next}(a[$0])' a b   #小括号可以不加

    $ awk 'FNR==NR{a[$0]=1;next}(a[$0]==1)' a b$ awk 'FNR==NR{a[$0]=1;next}{if(a[$0]==1)print}' a b

    $ awk 'FNR==NR{a[$0]=1}FNR!=NR&&a[$0]==1' a b

    说明:先要知道后面的a[$0]不是一个数组,而是通过下标(b文件每条记录)来访问a数组元素。如果a[b的一行记录]获取的a数组元素是1,则为真,也就是等于1,打印这条记录,否则获取不到元素,则为假。

    方法3:

    $ awk 'ARGIND==1{a[$0]=1}ARGIND==2&&a[$0]==1' a b

    $ awk 'FILENAME=="a"{a[$0]=1}FILENAME=="b"&&a[$0]==1' a b

    说明:ARGIND内置变量,处理文件标识符,第一个文件为1,第二个文件为2。FILENAME也是内置变量,表示输入文件的名字

    方法4:$ sort a b |uniq -d

    方法5:$ grep -f a b

    2)找不同记录(同上,取反)

            $ awk 'FNR==NR{a[$0];next}!($0 in a)' a b

            $ awk 'FNR==NR{a[$0]=1;next}!a[$0]' a b

            $ awk 'ARGIND==1{a[$0]=1}ARGIND==2&&a[$0]!=1' a b

            $ awk 'FILENAME=="a"{a[$0]=1}FILENAME=="b"&&a[$0]!=1' a b

            7

            8

            方法2:$ sort a b |uniq -d

            方法3:$ grep -vf a b

    3、合并两个文件

    1)将d文件性别合并到c文件

            $ cat c

            zhangsan 100

            lisi 200

            wangwu 300

            $ cat d

            zhangsan man

            lisi woman

    方法1:$ awk  'FNR==NR{a[$1]=$0;next}{print a[$1],$2}' c d

            zhangsan 100  man

            lisi 200 woman

            wangwu 300 man

    方法2:$ awk  'FNR==NR{a[$1]=$0}NR>FNR{print a[$1],$2}' c d

    说明:NR==FNR匹配第一个文件,NR>FNR匹配第二个文件,将$1为数组下标

    方法3:$ awk 'ARGIND==1{a[$1]=$0}ARGIND==2{print a[$1],$2}' c d

    2)将a.txt文件中服务名称合并到一个IP中

        $ cat a.txt

        192.168.2.100 : httpd

        192.168.2.100 : tomcat

        192.168.2.101 : httpd

        192.168.2.101 : postfix

        192.168.2.102 : mysqld

        192.168.2.102 : httpd

        $ awk -F: -vOFS=":" '{a[$1]=a[$1] $2}END{for(i in a)print i,a[i]}' a.txt

        $ awk -F: -vOFS=":" '{a[$1]=$2 a[$1]}END{for(i in a)print i,a[i]}' a.txt

        192.168.2.100 : httpd  tomcat

        192.168.2.101 : httpd  postfix

        192.168.2.102 : mysqld  httpd

    说明:a[$1]=$2 第一列为下标,第二个列是元素,后面跟的a[$1]是通过第一列取a数组元素(服务名),结果是$1=$2 $2,并作为a数组元素。

    3)将第一行附加给下面每行开头

        $ cat a.txt

        xiaoli

        a 100

        b 110

        c 120

        $ awk 'NF==1{a=$0;next}{print a,$0}' a.txt

        $ awk 'NF==1{a=$0}NF!=1{print a,$0}' a.txt

        xiaoli  a 100

        xiaoli  b 110

        xiaoli  c 120

    4、倒叙列打印文本

        $ cat a.txt

        xiaoli   a 100

        xiaoli   b 110

        xiaoli   c 120

        $ awk '{for(i=NF;i>=1;i--){printf "%s ",$i}print s}' a.txt

        100 a xiaoli

        110 b xiaoli

        120 c xiaoli

        $ awk '{for(i=NF;i>=1;i--)if(i==1)printf $i" ";else printf $i" "}' a.txt

    说明:利用NF降序输出,把最后一个域作为第一个输出,然后自减,print s或print ""打印一个换行符

    5、从第二列打印到最后

    方法1:$ awk '{for(i=2;i<=NF;i++)if(i==NF)prin

    tf $i" ";else printf $i" "}' a.txt

    方法2:$ awk '{$1=""}{print $0}' a.txt

        a 100

        b 110

        c 120

    6、将c文件中第一列放到到d文件中的第三列

        $ cat c

        a

        b

        c

        $ cat d

        1 one

        2 two

        3 three

    方法1:$ awk 'FNR==NR{a[NR]=$0;next}{$3=a[FNR]}1' c d

    说明:以NR编号为下标,元素是每行,当处理d文件时第三列等于获取a数据FNR(重新计数1-3)编号作为下标。

    方法2:$ awk '{getline f<"c";print $0,f}' d

        1 one a

        2 two b

        3 three c

    1)替换第二列

        $ awk '{getline f<"c";gsub($2,f,$2)}1' d

        1 a

        2 b

        3 c2)替换第二列的two

    $ awk '{getline f<"c";gsub("two",f,$2)}1' d

        1 one

        2 b

        3 three

    7、数字求和

    方法1:$ seq 1 100 |awk '{sum+=$0}END{print sum}'

    方法2:$ awk 'BEGIN{sum=0;i=1;while(i<=100){sum+=i;i++}print sum}'

    方法3:$ awk 'BEGIN{for(i=1;i<=100;i++)sum+=i}END{print sum}' /dev/null

    方法4:$ seq -s + 1 100 |bc

    8、每隔三行添加一个换行符或内容

    方法1:$ awk '$0;NR%3==0{printf " "}' a

    方法2:$ awk '{print NR%3?$0:$0" "}' a

    方法3:$ sed '4~3s/^/ /' a

    9、字符串拆分

    方法1:

        $ echo "hello" |awk -F '' '{for(i=1;i<=NF;i++)print $i}'

        $ echo "hello" |awk -F '' '{i=1;while(i<=NF){print $i;i++}}'

        h

        e

        l

        l

        o

    方法2:

        $ echo "hello" |awk '{split($0,a,"''");for(i in a)print a[i]}'  #无序

        l

        o

        h

        e

        l

    10、统计字符串中每个字母出现的次数

        $ echo a,b.c.a,b.a |tr "[,. ]" " " |awk -F '' '{for(i=1;i<=NF;i++)a[$i]++}END{for(i in a)print i,a[i]|"sort -k2 -rn"}'

        a 3

        b 2

        c 1

    11、第一列排序

     $ awk '{a[NR]=$1}END{s=asort(a,b);for(i=1;i<=s;i++){print i,b[i]}}' a.txt

    说明:以每行编号作为下标值为$1,并将a数组值放到数组b,a下标丢弃,并将asort默认返回值(原a数组长度)赋值给s,使用for循环小于s的行号,从1开始到数组长度打印排序好的数组。

    12、删除重复行,顺序不变

     

        $ awk '!a[$0]++' file

    博客地址:http://lizhenliang.blog.51cto.com

    QQ群:323779636(Shell/Python运维开发群)

    13、删除指定行

    删除第一行:

        $ awk 'NR==1{next}{print $0}' file #$0可省略

        $ awk 'NR!=1{print}' file

        $ sed '1d' file

        $ sed -n '1!p' file

    14、在指定行前后加一行

     

    在第二行前一行加txt:

        $ awk 'NR==2{sub('/.*/',"txt &")}{print}' a.txt

        $ sed'2s/.*/txt &/' a.txt

    在第二行后一行加txt:

    $ awk 'NR==2{sub('/.*/',"& txt")}{print}' a.txt

    $ sed'2s/.*/& txt/' a.txt

    15、通过IP获取网卡名

    $ ifconfig |awk -F'[: ]' '/^eth/{nic=$1}/192.168.18.15/{print nic}'

    16、浮点数运算(数字46保留小数点)

     

        $ awk 'BEGIN{print 46/100}'

        $ awk 'BEGIN{printf "%.2f ",46/100}'

        $ echo 46|awk '{print $0/100}'

        $ echo 'scale=2;46/100' |bc|sed 's/^/0/'

        $ printf "%.2f " $(echo "scale=2;46/100" |bc)

        结果:0.46

    17、替换换行符为逗号

        $ cat a.txt

        1

        2

        3

        替换后:1,2,3

    方法1:

    $ awk '{s=(s?s","$0:$0)}END{print s}' a.txt

    说明:三目运算符(a?b:c),第一个s是变量,s?s","$0:$0,第一次处理1时,s变量没有赋值初值是0,0为假,结果打印1,第二次处理2时,s值是1,为真,结果1,2。以此类推,小括号可以不写。

    方法2:

    $ tr ' ' ',' < a.txt

    方法3:

    $ sed ':a;N;s/ /,/;$!b a' a.txt

    说明:第一个标签a,先读取第一行记录1追加到模式空间,此时模式空间内容是1$,执行$!b($!最后一行不跳转,b是控制流跳转命令)跳转到a标签,继续读取第二行记录2追加到模式空间,因为使用N命令,每个记录以换行符( )分割,此时模式空间内容是1 2$,执行将换行符替换逗号命令,继续跳转到a标签...

    方法4:

     $ sed ':a;$!N;s/ /,/;t a' a.txt

    说明:与上面类似,其中t是测试命令,当上一个命令(替换)执行成功才跳转。

    方法5:

    $ awk '{if($0!=3)printf "%s,",$0;else print $0}' a.txt

    说明:3是文本最后一个数

    方法6:

    while read line; do

            a+=($line)

        done < a.txt

        echo ${a[*]} |sed 's/ /,/g'

    说明:将每行放到数组,然后替换

    18、把奇数换行符去掉

        $ cat b.txt

        string

        number

        a

        1

        b

        2

        $ awk 'ORS=NR%2?" ":" "' b.txt  #把奇数行换行符去掉

        $ xargs -n2 < a.txt  #将两个字段作为一行

        string number

        a 1

        b 2

    19、费用统计

        $ cat a.txt

        姓名             费用   数量

        zhangsan        8000    1

        zhangsan        5000    1

        lisi            1000    1

        lisi            2000    1

        wangwu          1500    1

        zhaoliu         6000    1

        zhaoliu         2000    1

        zhaoliu         3000    1

        统计每人总费用、总数量:

        $ awk '{name[$1]++;number[$1]+=$3;money[$1]+=$2}END{for(i in name)print i,number[i],money[i]}' a.txt

        zhaoliu 3 11000

        zhangsan 2 13000

        wangwu 1 1500

        lisi 2 3000

    20、打印乘法口诀

    方法1:

        $ awk 'BEGIN{for(n=0;n++<9;){for(i=0;i++<n;)printf i"x"n"="i*n" ";print ""}}'

        1x1=1

        1x2=2 2x2=4

        1x3=3 2x3=6 3x3=9

        1x4=4 2x4=8 3x4=12 4x4=16

        1x5=5 2x5=10 3x5=15 4x5=20 5x5=25

        1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36

        1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49

        1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64

        1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81

    方法2:

        #!/bin/bash

        for ((i=1;i<=9;i++)); do

           for ((j=1;j<=i;j++)); do

             result=$(($i*$j))

             #let "result=i*j"

             echo -n "$i*$j=$result "

           done

           echo

        done

    21、只打印奇数或偶数行

    打印奇数行:

    方法1:

    $ seq 1 5 |awk 'i=!i'

    说明:先知道对于数值运算,未定义变量初值为0,对于字符运算,未定义变量初值为空字符串。

    读取第一行记录,然后进行模式匹配,i是未定义变量,也就是i=!0,!取反意思。感叹号右边是个布尔值,0或空字符串为假,非0或非空字符串为真,!0就是真,因此i=1,条件为真打印第一条记录。

    没有print为什么会打印呢?因为模式后面没有动作,默认会打印整条记录。

    读取第二行记录,进行模式匹配,因为上次i的值由0变成了1,此时就是i=!1,条件为假不打印。

    读取第三行记录,因为上次条件为假,i恢复初值为0,继续打印。以此类推...

    可以看出,运算时并没有判断记录,而是利用布尔值真假判断。

    方法2:

    $ seq 1 5 |awk 'NR%2!=0'

    方法3:

    $ seq 1 5 |sed -n '1~2p'

    说明:步长,每隔一行打印一次

    方法4:

        $ seq 1 5 |sed -n 'p;n'

    说明:先打印第一行,执行n命令读取当前行的下一行2,放到模式空间,后面再没有打印模式空间行操作,所以只保存不打印,同等方式继续打印第三行。

        1

        3

        5

    打印偶数行:

        $ seq 1 5 |awk '!(i=!i)'

        $ seq 1 5 |awk 'NR%2==0'

        $ seq 1 5 |sed -n '0~2p'

        $ seq 1 5 |sed -n 'n;p'

  • 相关阅读:
    【郑轻邀请赛 G】密室逃脱
    【郑轻邀请赛 C】DOBRI
    【郑轻邀请赛 F】 Tmk吃汤饭
    【郑轻邀请赛 I】这里是天堂!
    【郑轻邀请赛 B】base64解密
    【郑轻邀请赛 A】tmk射气球
    【郑轻邀请赛 H】 维克兹的进制转换
    解决adb command not found以及sdk环境配置
    adb shell 命令详解,android, adb logcat
    Unexpected exception 'Cannot run program ... error=2, No such file or directory' ... adb'
  • 原文地址:https://www.cnblogs.com/howhy/p/6423422.html
Copyright © 2011-2022 走看看