• linux三剑客 awk


    awk

    本文是基于菜鸟教程awk的学习笔记和总结

    awk是一个文本处理工具,它会对文件的每一行进行处理,输出结果。

    基础语法:

    awk '{pattern actions}' files   # awk可以处理多个文件,注意是单引号
    

    常用变量:

    FS:文本分隔符,针对文本的每行,按照此分隔符分割
    NF:当前行分割后的字段数
    NR:当前行数
    RS:当前行的分隔符,通常是
    ,awk用此变量来分割确定每行数据。
    $0:当前行的内容
    $1:当前行的第一个字段;同理$2,$3,$4......
    IGNORECASE:值为1或0(真或假),用来进行是否忽略大小写匹配。
    FILENAME:当前文件名
    
    OFS:输出分隔符,它是用print输出信息时,这些变量之间的分割符号。
    ORS:输出行分隔符,输出时每行的分隔符
    FNR:当处理多个文件时,FNR显示的是当前文件的第几行。NR显示的是当前处理了多少行(多个文件时会累加)
    

    常用参数:

    -F:后接分隔符号,指定字段分割的符号,可以使用正则表达式。如:awk -F '[/:,]+' '{print $1}' file
    -v:后接变量,用来声明一个变量。如:awk -v a=1 '{a++} {print a}' file
    -f:后接awk文件,从文件读取awk命令。awk -f file.awk file2
    

    示例:

    现有文件a:

    $ cat a
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    

    -F:分割上述文本:

    $ awk -F '[:/]' '{print $1,$2}' a  # 用 :/ 这两个分隔符来分割
    root x
    bin x
    daemon x
    
    $ awk -F':' 'BEGIN{OFS="=";} {print $1,$2}' a  # 改变变量的分割符
    root=x
    bin=x
    daemon=x
    
    $ awk -F '[:/]' '{print $1 $2}' a   # print后面的变量用空格隔开,则字段直接合并了
    rootx
    binx
    daemonx
    

    -v:自定义变量:

    $ awk -v count=0 '{count++;print count}' a  # {}里面可以写多个action,并用;隔开
    1
    2
    3
    

    常用变量的使用:

    $ awk -F '[:/]' '{ print NR,NF,$0}' a
    1 10 root:x:0:0:root:/root:/bin/bash
    2 10 bin:x:1:1:bin:/bin:/sbin/nologin
    3 10 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    

    打印某行的信息:

    $ awk '{if(NR>1 && NR<4) print NR,$0}' a
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    

    正则匹配某个字段:

    • ~:针对字段使用正则匹配;如针对整行使用正则,可以省略;
    • /*/:两个/之间的内容,代表匹配的模式
    • !~:不匹配某个模式,针对字段使用,如针对整行,可以省略;
    • !/*/:不匹配两个/之间的内容
    $ awk -F ':' '$1 ~ /root/' a      # 针对字段1,匹配root
    root:x:0:0:root:/root:/bin/bash
    
    $ awk '/sbin/' a                 # 针对整行,匹配sbin
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    
    $ awk -F ':' '$1 !~ /root/' a        # 匹配字段1不是root的行
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    
    $ awk '!/sbin/' a                   # 匹配行中不带sbin的行
    root:x:0:0:root:/root:/bin/bash
    

    忽略大小写匹配:

    $ awk 'BEGIN{IGNORECASE=1} /ROOT/' a
    root:x:0:0:root:/root:/bin/bash
    

    BEGIN,END:

    awk 是对文件的每行进行处理,也就是说只有处理每行时,语句才会执行。如果你想要在处理文件的第一行之前,进行一些预设操作,需要用到BEGIN;如果想要在文件处理完最后一行之后,进行一些扫尾的操作,需要用到END。也就是说,BEGIN,END在处理整个文件的过程中,只在开头前和结尾后执行一次,在处理每行的过程中,它们是不会执行的。

    # BEGIN预定义一个count=0,每处理一行count+1,处理完最后一行后,END进行打印总数的操作。
    
    $ awk 'BEGIN{count=0} {count++} END{print "The file has line:",count}' a
    The file has line: 3
    

    数组:

    AWK 可以使用关联数组这种数据结构,索引可以是数字或字符串。

    AWK关联数 组也不需要提前声明其大小,因为它在运行时可以自动的增大或减小。

    语法:

    array[index]=value   # 声明数组
    delete array[index]  # 删除某个索引的值
    for (item in array) print array[item] # 数组的遍历,遍历的是索引,取值需要 array[item]
    

    声明数组并赋值:

    $ awk 'BEGIN{site["name"]="wang";site[1]=1;} END{print site["name"],site[1]}' a
    wang 1
    
    $ awk 'BEGIN{site["name"]="wang";site[1]=1;} END{ delete site["name"]; print site["name"],site[1]}' a  # 中间删除了name索引
     1
    
    统计文件词频:
    $ awk -F '[:/]' '{ for(a=1;a<=NF;a++) {if($a in array) array[$a]++ ;else if(length($a)!=0) array[$a]=1; }} END{for(aa in array) printf "%-10s %s
    ", aa,array[aa]} ' a | sort -t ' ' -nr -k2
    bin        4
    x          3
    sbin       3
    root       3
    nologin    2
    daemon     2
    2          2
    1          2
    0          2
    bash       1
    

    逻辑判断:

    条件判断之:if

    语法:

    if (condition)
    	action
    	
    
    
    if (condition){
    	action;
    	action;
    }
    

    例如:

    $ awk '{if(NR==2) print $0}' a
    bin:x:1:1:bin:/bin:/sbin/nologin
    
    
    $ awk '{if(NR==2) {print NR;print $0}}' a
    2
    bin:x:1:1:bin:/bin:/sbin/nologin
    

    条件判断之:if...else...

    语法:

    if(condition) 
    	action1;
    else
    	action2;
    

    示例:

    zhongtao.wang@GG678S2 MINGW64 ~/Desktop
    $ awk '{if(NR==2) print NR,$0; else print NR }' a
    1
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3
    

    条件语句之:if...else if... else if ... else ...

    语法:

    if(condition)
    	action1;
    else if(condition)
    	action2;
    else if(condition)
    	action3;
    ...
    else
    	action4;
    

    示例:

    $ awk '{if(NR==2) print NR,$0; else if(NR==3) print NR; else print "This is NR 1" }' a
    This is NR 1
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3
    
    

    for 循环

    语法:

    for (initialisation; condition; increment/decrement)
        action
    

    示例:

    $ echo "haha" | awk '{ for (i=1;i<=10;i++) print i }'
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    

    while 循环:

    语法:

    while (condition)
    	actions;
    

    示例:

    $ echo "haha" | awk '{ a=1; while(a<=10) {print a;a++ } }'
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    

    break 跳出循环:

    $ echo "haha" | awk '{ a=1; while(a<=10) {print a;a++;break } }'
    1
    

    continue 继续循环:

    continue会让跳过循环内的代码,直接进行下一次循环

    $ echo "haha" | awk '{ a=1; while(a<=10) {if (a==5) {a++;continue;} print a;a++;} }'
    1
    2
    3
    4
    6
    7
    8
    9
    10
    

    exit 退出脚本

    $ echo "haha" | awk '{ a=1; while(a<=10) {print a;a++; if(a==5) exit; } }'
    1
    2
    3
    4
    

    字符函数:

    字符替换:gsub,sub

    gsub 将替换 str 中所有的 old 为 new,而 sub 只替换一次,两者语法相同:

    gsub(old,new,str) / sub(old,new,str)
    

    示例:

    $ echo 'haha' | awk '{ str="hahahahaha"; gsub("ha","I",str);print str }'
    IIIII
    
    $ echo 'haha' | awk '{ str="hahahahaha"; sub("ha","I",str); print str }'
    Ihahahaha
    
    

    字符截取 substr

    语法:

    substr(str, start, end)   # 截取 str 的start-end(包含start,end),如果没写end,则到最后
    

    示例:

    $ echo 'haha' | awk '{ str="hahahahaha"; s = substr(str,1,2); print s}'
    ha
    

    字符索引 index

    语法:

    index(str1,str2)  # 返回 str2 在 str1 中的索引位置,如果没有找到,返回0
    

    示例:

    $ echo 'haha' | awk '{ str="one t two three"; s = "two"; print index(str,s)}'
    7
    

    字符串长度:length

    语法:

    length(str)
    

    示例:

    $ echo 'haha' | awk '{ str="one t two three"; print length(str)}'
    15
    

    字符串分割 split

    语法:

    split(str,array,',')  # 将str用','分割,每个元素存放在arrary里面,如果没指定分隔符,则用 FS
    

    示例:

    $ echo 'haha' | awk '{ str="one t two three"; split(str,array); for (arr in array) print array[arr]; }'
    one
    t
    two
    three
    

    字符串大小写转换:tolower(),toupper()

    语法:

    tolower(str) / toupper(str)
    

    示例:

    $ echo 'haha' | awk '{ str="one two three"; print tolower(str) "
    " toupper(str) }'
    one two three
    ONE TWO THREE
    

    时间

    获取时间戳 systime

    语法:

    systime()  # 返回从1970年1月1日开始到当前时间(不计闰年)的整秒数
    

    示例:

    $ echo 'haha' | awk '{ print systime(); }'
    1602483391
    

    时间戳格式化输出 strftime

    语法:

    strftime(format,timestamp)
    

    示例:

    $ echo 'haha' | awk '{ print strftime("Time = %m/%d/%Y %H:%M:%S", systime()) }'
    Time = 10/12/2020 14:20:41
    

    其他命令

    执行系统命令 system(command)

    执行特定的命令然后返回其退出状态。返回值为 0 表示命令执行成功;非 0 表示命令执行失败。

    示例:

    $ echo 'a' | awk '{ ls=system("ls 'chrom*'"); print ls}'
    chrome.lnk    # 这句话是 ls=system("ls 'chrom*'") 执行时显示的
    0            # 这个是 print ls 才显示的。
    

    跳过当前行,处理下一行数据 next

    next 可以让 awk 停止处理当前记录,直接进行下一行记录的处理

    $ awk '{ if(NR==2) next; print $0; }' a
    root:x:0:0:root:/root:/bin/bash
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    

    问题:awk什么时候该加{}啊?

    首先,awk的语法是awk '{pattern action}' file, 其中 pattern,其实就是各种判断语句(if,while等各种条件),action 就是正常的执行操作(如赋值:a=1; 打印:print a;),当在一个 pattern 下进行多种操作时(多个action,每个action用;隔开,如a=1;a++;print a;),为了保证这些action都是作用于当前pattern下,需要把这些actions用{}包裹起来。否则,就只有pattern后跟的第一个 action 作用于当前 pattern 下。

    譬如:下面是个死循环哦

    $ echo 'haha' | awk '{a=1; while(a<10) print a; a++; }' 
    # 格式化一下上面的语句,其实是这样的:
    echo 'haha' | awk '{
    	a=1; 
    	while(a<10) 
    		print a; 
    	a++;          # 因为a++;不在循环里,所以是个死循环
    }' 
    

    不想变成死循环,加个{}就好了:

    $ echo 'haha' | awk '{a=1; while(a<10) {print a; a++;} }'
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    # 上面的语句等价于:
    echo 'haha' | awk '{
    	a=1; 
    	while(a<10) {
    		print a; 
    		a++;      # a++; 在循环里面,每次+1,当a=10就跳出循环了。
    	} 
    }'
    
    

    附录:运算符

    运算符 描述
    =, +=, -=, *=, /=, %=, ^=, **= 赋值
    ?: 三目运算;echo "a" | awk '{a=1;print a==2?"yes":"no"}' 结果是no
    || 逻辑或
    && 逻辑与
    ~ 和 !~ 匹配正则表达式和不匹配正则表达式
    <, <=, >, >=, !=, == 关系运算符
    空格 连接
    +, - 加,减
    *, /, % 乘,除与求余
    +, -, ! 一元加,减和逻辑非
    ^, *** 求幂
    ++, -- 增加或减少,作为前缀或后缀;如a=1;a++
    $ 字段引用;如 $1
    in 数组成员
  • 相关阅读:
    hdu 1201 18岁生日
    线性代数
    关于pymongo的一些说明
    利用数组进行数据处理
    通用函数:快速的元素级数组函数
    IPython:一种交互式计算和开发环境
    关于一道面试题的思考
    wireshark中的抓包过滤器和显示过滤器
    wireshark推荐书籍
    wireshark 找不到网卡的解决办法
  • 原文地址:https://www.cnblogs.com/wztshine/p/13803203.html
Copyright © 2020-2023  润新知