美文网首页笔戈 Web Team
linux中强大的sed和awk(上)

linux中强大的sed和awk(上)

作者: chrisxlq | 来源:发表于2015-12-15 15:35 被阅读1532次

    最近多了很多查找编辑文件和分析日志的需求,之前只是浅浅的知道sed,awk大致的用法,这段时间学下来才发现,sed和awk真是强大。

    awk

    awk更擅长对文件进行分析和列的操作。

    条件类型加动作在接文件,这里条件类型加动作为一组,一条命令中可以放多组。花括号{}中支持 print 的格式, if, while, for ,逻辑判断等等。

    $ awk '{pattern + action}' {filenames}
    
    域编辑

    例如,在我们需要输出 test.log 的第一列:

    [root@localhost ~]# awk  '{print $1}' test.log
    192.29.7.26
    192.29.7.14
    192.26.2.26
    192.15.25.26
    

    awk是这样操作的,读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域。$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是"空白键" 或 "[tab]键",所以$1代表第一列代表IP。
    使用-F,可指定分隔符,如:

    [root@localhost ~]# awk  -F '"'  '{print $1}' test.log 
    192.29.7.26 - - [14/Dec/2015:20:58:18 +0800] POST /praise HTTP/1.1 
    192.29.7.14 - - [14/Dec/2015:20:58:19 +0800] GET /api HTTP/1.1 
    192.26.2.26 - - [14/Dec/2015:20:58:19 +0800] GET /api HTTP/1.1 
    192.15.25.26 - - [14/Dec/2015:20:58:19 +0800] GET /api HTTP/1.1
    

    也可指定打印的分割符,以下打印第一和第四列,使用tab陈列。

    [root@localhost ~]# awk '{print $1"\t"$4}' test.log 
    

    还有很多:

    [root@localhost ~]# awk '/200/' text.log     //搜索文件中匹配200字符的行
    [root@localhost ~]# awk '{print NR,NF,$1,$NF}' test.log    //显示文件file的当前记录号、域数和每一行的第一个和最后一个域
    [root@localhost ~]# awk '/string/{print "\047 good \047"}{print $1,$2}' test.log    //找到匹配对象string,在其后输出特定符号,/047代表带引号
    [root@localhost ~]# awk   'BEGIN { OFS="%"} {print $1,$2}'  test.log    //通过输出%,改变日志的格式
    [root@localhost ~]# awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'    //可以在输入前后加入特定的标识,常用于脚本中
    

    合并拆分文件系列:

    [root@localhost ~]awk '{ print $0 }' file1 file2 file3>file  //酱file1,file2,file3合并成file
    
    

    awk无需在变量前添加$符号,这是与shell不一样的地方,上面的例子用到一些变量,在awk中善于运用变量会使工具用途大大增加。以下为各变量的含义。

    ARGC        命令行变元个数 
    ARGV        命令行变元数组 
    FILENAME    当前输入文件名 
    FNR  当前文件中的记录号 
    FS   输入域分隔符,默认为一个空格 
    RS   输入记录分隔符 
    NF   当前记录里域个数 
    NR   到目前为止记录数 
    OFS  输出域分隔符 
    ORS  输出记录分隔符 
    
    数组与自定义变量

    除了awk的内置变量,awk还可以自定义变量。

    [root@localhost ~]#  awk '{count++;print $1;} END{print count}' test.log 
    192.29.7.26
    192.29.7.14
    192.26.2.26
    192.15.25.26
    4
    

    比如刘老师说想看,每分钟的请求数,以下可以将每分钟的请求数列出:

    [root@localhost ~]# awk -F: '{count[$2":"$3]++} END {for (minute in count) print minute, count[minute]}' test.log 
    20:58 4
    

    使用数组可以将日志中IP的请求数统计出来

    [root@localhost ~]# awk '{a[$1]+=1;}END{for(i in a){print a[i]" " i;}}' test.log
    
    复合表达式

    可以使用&&或||连接多个表达式,表达式用()扩起
    (expr1) && (expr2)
    (expr1) ||(expr)

    比如需要查看日志中某一时间断的请求数:

    awk '$4>="[01/Dec/2015:15:00:00"&&$4<="[01/Dec/2015:22:00:00"' test.log
    
    IF

    和C语言一样,基本格式是这样的

    if (expression1) {
        action1
    } else if (expression2) {
        action2
    } else {
        action3
    }
    

    来个栗子🌰
    有如下文本,要求:将第一列中重复的合并为一行,其第二列填入最长地址的那列

    0001|hi
    0002|dog
    0001|It's a good day
    0003|cat
    0001|nice
    0004|linux

    得到的结果应为:

    0001|It's a good day
    0002|dog
    0003|cat
    0004|linux

    代码:

    #!/bash/bin
    BEGIN{FS=OFS="|"; i=1;}
    { if(a[$1]==0){b[i]=$1;a[$1]=$2;i++}
    if(length(a[$1])}
    END{for(j=1;j}
    

    比较代码:(实现不全)

    awk 'BEGIN{FS=OFS="|"} !(length(a[$1])>length($2)){a[$1]=$2} END{for(i in a)print i,a[i]}' data.txt
    

    解释:此例中,用了两个数组,a用来与$1关联,b用来顺序记录,使得在最后打印时是完全按照$1顺序打印。条件句首先判断数组元素是否是第一次写入,若非,则比较当前$2值和以前储存的值长度。
    功能不全代码不能顺序打印。当$1有重复,而$2长度第一次、第二次、第三次是以递减的方式时,该代码应用得较好。但是,当$2各次得到的长度不确定时,代码不能实现上述功能。例如:本例中第5行的第二列若比第3行的第二列长度长时,功能不全代码就不能实现要求。

    相关文章

      网友评论

      • 吉大六爷:你应该把你的测试文件test.log发出来,这样读者才能边看边做实验

      本文标题:linux中强大的sed和awk(上)

      本文链接:https://www.haomeiwen.com/subject/ndsuhttx.html