美文网首页Linux
Linux-grep、sed、awk之awk命令

Linux-grep、sed、awk之awk命令

作者: Akuooo | 来源:发表于2021-11-25 09:27 被阅读0次

    参考:
    Linux三剑客(grep sed awk) 之 awk
    awk从放弃到入门
    The GNU Awk User’s Guide

    awk是一个报告生成器,支持条件判断、数组、循环等功能,可以将文本整理成我们想要的表格形式。awk逐行处理,默认按照空格作为分隔符,若有多个空格,则将连续的空格作为分隔符。

    一、awk基础

    1. 普通模式
    awk [options] 'program' file1,file2
    

    program = pattern+action

    awk [options] 'Pattern{Action}' file
    

    awk常用动作为print和printf

    1. 特殊模式
    awk 'BEGIN{coms}/pattern/{coms}END{coms}'
    

    1)BEGIN和END模块只能有一个,中间的pattern匹配可以有多个
    2)BEGIN:代表awk在处理文本前要做的事情,即使无文件名,仅用BEGIN也能正常输出

    awk 'BEGIN{print "111","222"}'
    

    3)END:代表awk在处理文本后要做的事

    awk '{print 1,2}END{print'333','444'}'test
    
    1. 内置变量
    变量名 属性 备注
    $0 当前一整行
    $1~$n 当前记录的第n个字段 awk '{print "str:"$1'}'
    FS 输入字段分隔符,默认为space awk -F ':' awk -v FS=':'
    RS 输入记录分隔符,默认为\n 如果RS=“”,会以空白行分隔
    OFS 输出字段分隔符,默认space
    ORS 输出的记录分隔符,默认\n
    NF 当前记录中的字段个数,即多少列
    NR 行号,从1开始
    FNR 各文件分别显示行号
    FILENAME 当前文件名 awk '{print FILENAME,$0}'
    ARGC 命令行参数的个数
    ARGV 数组,保存的是命令行给定的参数 ARGV[0]是awk,单引号中的不算参数,处理的文件是参数
    1. 自定义变量
      1)-v varname=value
    $awk -v myVar="test" 'BEGIN{print myVar}'
    $abc=666
    $awk -v myvar=$abc 'BEGIN{print myvar}'
    

    2)在program中定义

    awk 'BEGIN{myvar="ttt";print myvar}'
    

    tips:赋值时不要在等号左右加空格,我写R的时候习惯性啥都加空格,于是就报错啦

    二、printf

    1. echo和printf
      两者都是输出文本命令,echo输出字符串末尾会自动加上\n;printf则不会,\n需要指定。
      printf的优势在于可以用格式替换符来处理一长串的str

    格式替换符

    名称 含义
    %s 字符串
    %f 浮点格式
    %b 对应参数包含转义字符时,对应转义字符会被转义
    %c ASCII字符,显示对应擦书第一个字符
    %d,%i 十进制整数
    %o 不带正负号的八进制值
    %u 不带正负号的十进制值
    %x 不带正负号的十六进制值,用af表示1015
    %X 不带正负号的十六进制,用AF表示1015
    %% 表示‘%’本身
    转义字符
    名称 含义
    \a 警告字符,常为ASCII的BEL字符
    \b 后退
    \c 不显示
    \f 换页
    \n 换行
    \r 回车
    \t 水平制表符
    \v 垂直制表符
    \\ “\”本身
    \ddd 表示1~3位数八进制的字符串,仅在字符格式串中有效
    \0ddd 表示1~3位数八进制值的字符串
    修饰符
    参数 含义
    %7s 7代表当前替换符对应的输出长度为7个字符宽,不足补齐,超出也正常显示
    %-7s “-”表示左对齐,不加时为右对齐
    %+5d 正数会自动变为+num
    %12.3f “.3”表示保留小数点后三位,%f默认是小数点后6位
    %12.5d “.5”表示正数的长度,不足用0补齐
    1. awk的printf动作
      注意:
      输出文本不会换行,要手动加\n;
      “指定的格式”与“被格式化的文本”间要用“逗号”隔开
      “格式替换符”与“被格式化的文本”数量一一对应
    $ awk -v FS=':' 'BEGIN{printf "%-10s\t %s\n","用户名称","用户ID"} {printf "%-10s\t %s\n",1,3}' /etc/passwd
    用户名称         用户ID
    1                3
    1                3
    1                3
    

    三、awk模式(Pattern)

    1. grep和awk
    grep '^root' /etc/password
    awk '/^root/{print $0}' /etc/passwd
    
    1. 注意
      1)awk中的正则是扩展正则表达式
      2)在使用{x,y}或[[:space]]时,要加上参数--posix
      3)注意""和"."的转义

    3.awk行范围模式

    awk '/正则表达式/{动作}'  file
    awk '/正则1/,/正则2/{动作}' file
    

    两个正则就是行范围模式,从正则1匹配的行开始,到正则2匹配的行结束

    匹配符 含义
    ~ 匹配后面的正则 '$1~/pattern/'
    !~ 不匹配后面的正则 '$1!~/pattern/'

    示例

    $ cat test.txt
    sdsfhu
    djfia
    I love you
    I hate you
    Oh/my god
    $ awk '/^Oh\//{print $0}' test.txt
    Oh/my god
    $ awk --posix '/[[:space:]]/{print $0}' test.txt
    I love you
    I hate you
    Oh/my god
    $ awk '/love/,/hate/{print $0}' test.txt
    I love you
    I hate you
    $ awk 'NR>=2 && NR<=4{print $0}' test.txt
    djfia
    I love you
    I hate you
    

    四、awk动作总结

    {}:“组合语句”类型的动作,将多个代码组合成代码块
    print $0:“输出语句”类型

    1. if动作
    $ awk '{if(NR == 1){print $0}}' test.txt
    sdsfhu
    #if对应的{},若只有一条命令,可以省略{}
    $ awk '{if(NR == 1) print $0}' test.txt
    sdsfhu
    $ awk '{if(NR == 1){print $1;print $2}}' test.txt
    $ awk -F ":" '{if($3 <500){print $1,"系统用户"}else {print $1,"普通用户"}}' file
    
    1. for
    $ awk 'BEGIN{for(i=1;i<=6;i++){print i}}'
    1
    2
    3
    4
    5
    6
    

    3.while

    $ awk -v i=1 'BEGIN{while(i<=5){print i;i++}}'
    1
    2
    3
    4
    5
    $ awk 'BEGIN{i=1;while(i<=5){print i;i++}}'
    1
    2
    3
    4
    5
    
    1. do...while
    #打印1遍test
    $ awk 'BEGIN{i=1;do{print "test";i++}while(i<1)}'
    test
    #打印5遍test
    $ awk 'BEGIN{do{print "test";i++}while(i<=5)}'
    test
    test
    test
    test
    test
    test
    
    1. continue和break
    #打印0~5,但不打印3
    $ awk 'BEGIN{for(i=0;i<6;i++){if(i==3){continue};print i}}'
    0
    1
    2
    4
    5
    #打印0~2
    $ awk 'BEGIN{for(i=0;i<6;i++){if(i==3){break};print i}}'
    0
    1
    2
    
    1. exit
      表示跳过所有后续动作,直接执行END内的命令;如果没有END模式,则直接结束awk命令
    #只打印1
    $ awk 'BEGIN{print 1;exit;print 2;print 3}'
    1
    #不打印$0
    $ awk 'BEGIN{print "start";exit} {print $0} END{print "over"}' test.txt
    start
    over
    
    1. next
      跳过当前行,直接从下一行开始处理
    #跳过第二行
    $ awk '{if(NR==2){next};print $0}' test.txt
    sdsfhu
    I love you
    I hate you
    Oh/my god
    

    这些命令感觉和C语言中的差不多~

    五、awk数组

    1. 基础概念
      1)awk中数组是一个使用字符串作为下标的“关联数组”
      2)使用时可用数字/字符串作为下标,使用数字作为下标时,awk默认把“数字”下标转换为“字符串”
      3)awk中,元素值可以设置为“空”
      4) 当一个元素不存在于数组时,若直接引用这个不存在的元素,awk会自动创建这个元素,并默认为这个元素赋值为“空字符串”
      5) awk中,判断数组元素中是否存在,用“if(下标 in 数组名)”
      6)split函数生成的数组,下标默认从1开始
    2. 基本操作
    #创建数组,可直接创建
    $ awk 'BEGIN{ a[0]="一";a[1]="二";a[2]="三";print a[0]}'
    一
    #删除数组元素
    $ awk 'BEGIN{a[0]="一";a[1]="二";a[2]="三";delete a[0]}'
    #删除整个数组
    $ awk 'BEGIN{a[0]="一";a[1]="二";a[2]="三";delete a}'
    #for循环有序遍历数组,下标需要是数字
    $ awk 'BEGIN{a[0]="一";a[1]="二";a[2]="三";for(i=1;i<=2;i++){print i,a[i]}}'
    1 二
    2 三
    #for循环无序遍历数组
    $ awk 'BEGIN{a[0]="一";a[1]="二";a[2]="三";for(i in a){print i,a[i]}}'
    0 一
    1 二
    2 三
    

    六、awk内置函数

    1. 算术函数
      1)rand 生成随机数
      2)srand 固定打印1,与rand合用可生成小于1的随机数
      3)int 取整
    awk 'BEGIN{srand();print rand()}'
    #随机数乘以100,通过int函数调整,生成0~100间的随机数
    awk 'BEGIN{srand();print int(100*rand())}'
    
    1. 字符串函数
      1)gsub:将指定范围内匹配到的字符全部替换为新字符
      2)sub:与gsub类似,但只能替换范围内第一次匹配到的字符
    awk '{gsub("you","me",1);print 0}' test.txt
    awk '{sub("you","me");print }' test.txt
    

    3)length:获取指定字符串长度
    4)index:获取指定字符串位于整个字符串中的位置
    5)split:返回数组长度

    1. 排序函数
      1)asort:根据数组value值进行排序。排序后,原有key会被数字替代
      2)asorti:排列原数组

    七、三元运算

    语法
    条件?结果1:结果2

    1.三元运算替换if…else

    #if...else
    awk -F : '{if($3<500){usertype="系统用户"}else{usertype="普通用户"};\print $1,usertype}' /etc/password
    #三元运算符
    awk -F : '{usertype=$3<500?"系统用户":"普通用户";\print 
    $1,usertype}' /etc/passwd
    

    $3<500:条件判断
    ?"系统用户":为真,则usertype=系统用户
    :"普通用户":为假,则usertype=普通用户

    #统计系统用户和普通用户数量
    awk -F : '{$3<500?a++:b++}END{print a,b}' /etc/passwd
    
    1. 打印奇数偶数行
    #打印奇数行
    $ awk 'i=!i' test.txt
    sdsfhu
    I love you
    Oh/my god
    #打印偶数行
    $ awk '!(i=!i)' test.txt
    djfia
    I hate you
    

    解析
    1)awk中,若省略了模式对应的动作,当前行满足模式时,默认动作为打印整行,即{print $0}
    2)awk中,0或者空字符串表示“假”,非0值或者非空字符串表示“真”

    $ awk '/o/{print $0}' test.txt
    I love you
    I hate you
    Oh/my god
    $ awk '/o/' test.txt
    I love you
    I hate you
    Oh/my god
    

    从上可看出,若省略了对应动作,默认输出整行,即'{print $0}'。BEGIN/END模式除外
    那么将模式替换为“真”或“假”

    接下来的可以自仔细琢磨参考博文的内容:https://www.zsythink.net/archives/2159
    我自己讲不清楚了/捂脸,慢慢悟吧呜呜

    $ awk '{i=!i;print i}' test.txt
    1
    0
    1
    0
    1
    

    可以看到,打印出i值,第一行为1,;然后再取反值,则为0
    因此,在打印奇数行时,因为i最开始不为0,所以这一行被打印
    (我也被自己绕晕了,总之就是这样能打印出来奇数行。。)
    偶数行同理,只不过是再取一个反值

    相关文章

      网友评论

        本文标题:Linux-grep、sed、awk之awk命令

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