• 43.linux三剑客之awk


    1.awk1:

    1.awk基础
    	vawk [options] 'Pattern{Action}' file # 语法格式
        echo ddd >> testd
        awk '{print}' testd
        awk '{print $5}' testd   #代表输出第五列的参数,没有指定分隔符默认使用空格,-F制定分隔符
    	awk 'print $1,$2' test   #输出第一列和第二列,逗号表示输出内容使用空格分开
    2.awk模式
    	AWK 包含两种特殊的模式:BEGIN 和 END
    	BEGIN 模式指定了处理文本之前需要执行的操作:
    	END 模式指定了处理完所有行之后所需要执行的操作:
        awk 'BEGIN{print "aaa", "bbb"}{print $1}END{"game over"}' # 表示在开始输出aaa bbb ,结束之后输出gameover,中间的就是处理的行
        作用:可以用来添加表头和标题
    3.awk分隔符
        awk有哪些分隔符,awk的默认分割符是空格,但是,这样描述并不精确,因为,awk的分隔符还分为两种,"输入分隔符 FS" 和 "输出分隔符OFS"
        # 输入
        awk -F # '{print $1,$2}' test  # 制定以#输入分割
        awk -v FS='#' '{print $1,$2}' test  # 制定以#输入分割
        # 输出
        awk -v OFS='+++' '{print $1,$2}' test  # 制定以+++输出分割
        
        awk '{print $1$2}' test  # 不使用分隔符
        awk '{print $1 $2}' 表示每行分割后,将第一列(第一个字段)和第二列(第二个字段)连接在一起输出。
    
    awk '{print $1,$2}' 表示每行分割后,将第一列(第一个字段)和第二列(第二个字段)以输出分隔符隔开后显示。
    
    4.变量
         FS:输入字段分隔符, 默认为空白字符
        awk -v FS='#' '{print $1,$2}' test  # 制定以#输入分割
        
        OFS:输出字段分隔符, 默认为空白字符
        awk -v OFS='+++' '{print $1,$2}' test  # 制定以+++输出分割
        
        RS:输入记录分隔符(输入换行符), 指定输入时的换行符
         我们不想以默认的"回车换行"作为"行分隔符",而是想使用空格作为所谓的行分隔符,也就是说,我们想让awk认为,每遇到一个空格,
    就换行,换句话说,我们想让awk以为每次遇到一个空格就是新的一行
        akw -v RS=' ' '{print NR,$0}'
        
        ORS:输出记录分隔符(输出换行符),输出时用指定符号代替换行符
        让awk认为,"+++"才是真正的输出行分隔符
        awk -v ORS='+++' '{print NF,$0}' test1
        awk -v ORS='+++' -v RS='' '{print NF,$0}' test1
        
        NF:number of Field,当前行的字段的个数(即当前行被分割成了几列),字段数量
        awk -v ORS='+++' -v RS='' '{print NF,$0}' test1
        3 1 2 3
        
        NR:行号,当前处理的文本行的行号。
        awk '{print NR,NF}' test  # 输出每一行的行号和列数
        
        FNR:各文件分别计数的行号
        awk '{print FNR,$0}' test test1  # 分别对每个文件的行数进行计数
        
        FILENAME:当前文件名
        awk '{print FILENAME,FNR,$0}' test test1
        
        ARGC:命令行参数的个数
        awk 'BEGIN{print "aaa",ARAV[0],ARGV[1],ARGV[2],ARGC}' test2 test1 # ARAV[0]表示awk本身,ARGC表示数组的长度
        aaa awk test1 test2 3 
        
        ARGV:数组,保存的是命令行所给定的各参数
        awk 'BEGIN{print "aaa",ARGV[1] }' test1 test2
        aaa test1
    	awk 'BEGIN{print "aaa",ARGV[1],ARGV[2]}' test2 test1
        aaa test2 test1
        awk 'BEGIN{print "aaa",ARAV[0],ARGV[1],ARGV[2]}' test2 test1 # ARAV[0]表示awk本身
        aaa awk test1 test2
    
    5.自定义变量
    	方式一:
        abc="6666"
        awk -v myvar=$abc 'BEGIN{print myvar}'
        666
        awk -v myvar="testvar" 'BEGIN{print myvar}' 
        testvar
        方式二:
        awk -v 'BEGIN{myvar="testvar"; myvar2="testvar2";print myvar}'
        testvar    testvar2
        
    6.awk格式化
    	awk 'BEGIN{print $1}' test1
        abc
        8yy
        awk 'BEGIN{printf $1}' test1
        abc 8yy
        awk 'BEGIN{printf "%s
    " , $1}' test1  # 需要使用逗号隔开
        abc 
        8yy
        printf "%s
    " teststring
        teststring
        printf "%s
    " 1 2 3 4 5
        1
        2
        3
        4
        5
        
        awk 'BEGIN{printf "%s
    " , 1,2,3,4,5}' 
        1
        awk 'BEGIN{printf "%s
    " , $1}' 
        awk 'BEGIN{printf "%s
    %s
    " , 1,2,3,4,5}'  # 必须与传入的参数数量相同
        1
        2
        总结:
        1)使用printf动作输出的文本不会换行,如果需要换行,可以在对应的"格式替换符"后加入"
    "进行转义。
        2)使用printf动作时,"指定的格式" 与 "被格式化的文本" 之间,需要用"逗号"隔开。
        3)使用printf动作时,"格式"中的"格式替换符"必须与 "被格式化的文本" 一一对应。
        
        cat test1
        abc 123 iuy ddd
        awk 'printf "第一列: %s 第二列: %s
    " , $1,$2 ' test1
        第一列: abc 第二列:123
        
        cat test1
        abc#123#iuy#ddd
        awk -v FS='#' 'printf "第一列: %s 第二列: %s
    " , $1,$2 ' test1
        第一列: abc 第二列:123
        
        awk -v FS='[ ]+' 'BEGIN{printf "%-10s	 %s
    " , "用户名", "用户ID"}{printf "%-10s	 \%
    " , $1,$2}' test1
        用户名称     用户ID
        abc			123
    
    7.awk模式
    	cat test2
        anc afds vasdf casdf dfdf
        asf fd
        fdsa fdf 56
        
        awk 'NF==5 {print $0}' test2
        anc afds vasdf casdf dfdf
        
        awk 'NF>2 {print $0}' test2
        anc afds vasdf casdf dfdf
        asf fd
        fdsa fdf 56
        
        awk 'NF<4 {print $0}' test2
        asf fd
        fdsa fdf 56
        
        awk '$1==asf {print $0}' test2
        asf fd
    
    关系运算符 含义 用法示例
    < 小于 x < y
    <= 小于等于 x <= y
    == 等于 x == y
    != 不等于 x != y
    >= 大于等于 x >= y
    > 大于 x > y
    ~ 与对应的正则匹配则为真 x ~ /正则/
    !~ 与对应的正则不匹配则为真 x !~ /正则/
    	1、空模式  # 不适用任何模式就是空模式
    	2、关系运算模式
    	3、正则模式
    	4、行范围模式
    	5、BEGIN/END模式    
        
    8.正则模式
    	awk '/^zsy/{print $0}' /etc/passwd  # 找出以zsy开头的行
        唯一的区别就是,在grep命令中,直接使用了正则表达式,而在awk命令中,正则表达式被放入了两个斜线中。
        
        awk -v FS=':' 'BEGIN{printf "%-10s	 %s
    " , "用户名", "用户ID"}/^zsy/{printf "%-10s	 %
    " , $1,$2}' /etc/passwd
        1、从/etc/passwd文件中找出符合条件的行(用户名以zsy开头的用户)。
    	2、找出符合条件的文本行以后,以":"作为分隔符,将文本行分段。
    	3、取出我们需要的字段,格式化输出。
    	4、结合BEGIN模式,输出一个格式化以后的文本,提高可读性。
        
        awk '//bin/bash$/{print $0}'  /etc/passwd  # 找出以/bin/bash结尾的行
        
        cat tests3
        hey
        heey
        heeey
        heeeey
        
        awk -r '/he{2,3}/{print $0}' test3   # -r使用扩展正则
        heey
        heeey
        
    9.awk行模式范围
    	cat -n test4
        1 allent phillips
        2 green lee
        3 william aiden james lee
        4 angle jack
        5 tyler kevin
        6 lucas thomas
        7 kevin
        
    	akw '/lee/,/kevin/{print NR,$0}' test4 # 匹配从出现lee的行到kevin的行
        2 green lee
        3 william aiden james lee
        4 angle jack
        5 tyler kevin
        
        awk 'NR=>2 && NR<=5{print NR,$0}' test4
        2 green lee
        3 william aiden james lee
        4 angle jack
        5 tyler kevin
    
    关系运算符 含义 用法示例
    < 小于 x < y
    <= 小于等于 x <= y
    == 等于 x == y
    != 不等于 x != y
    >= 大于等于 x >= y
    > 大于 x > y
    ~ 与对应的正则匹配则为真 x ~ /正则/
    !~ 与对应的正则不匹配则为真 x !~ /正则/
    	cat test5
        192.168.231.16
        10.0.0.1
        10.15.13.1
        192.168.131.176
        192.168.71.154
        
        awk -r '$2~/192.168.[0-9]{1,3}.[0-9]{1,3}/{print $1,$2}' test5
        192.168.231.16
        192.168.131.176
        192.168.71.154
        
        
    10.awk动作
        cat test6
        he  y
        he  ey
        he eey
        he  eeey
        
        awk -r '{print $0}{print $1}' test3  # 组合语句
        he 
        y
        he 
        ey
        he 
        eey
        he 
        eeey
        
    11.akw条件语句
    	if语句:
    	awk -r '{print $0 ;print $1}' test3  # 组合语句 ,等价于上面
        
        awk ' {if(NR==1){print $0}}'   # 条件语句
        
        awk '{if(NF==1){print $1} else{print $2}}' /etc/passwd
        awk '{if(NF==1){print $1} else if(NF==2 && NF>3){print $0} else{print $2}}' /etc/passwd  #多分支
        
        循环语句:
        awk 'BEGIN{ for(i=1;i,=6;i++){print i}}'
        1
        2
        3
        4
        5
        6
        
        awk -v i=1 "BEGIn{ while(i<=5){print i;i++}}"
        1
        2
        ..
        
        awk 'BEGIn{i=1;while(i<=5){print i;i++}}'  # 同上
        
        akw 'BEGIn{i=1;do{print "test"; i++} while(i<1)}'
        test
        
        akw 'BEGIn{do{print "test"; i++} while(i<5)}' #无论如何都执行一次都之后的语句
        test
        test
        ..
        
        关键字:
        continue的作用:跳出"当前"循环
    	break的作用:跳出"整个"循环
        exit的作用:跳过awk执行语句,执行END中的内容
        next的作用:跳过这行去执行接下来的行
        awk 'BEGIN{for(i=0;i<6;i++){print i}}'
        awk 'BEGIN{for(i=0;i<6;i++){if(i==3){continue};print i}}'
        0
        1
        2
        4
        5
        awk 'BEGIN{for(i=0;i<6;i++){if(i==3){break};print i}}'
        0
        1
        2
    	
        # exit直接结束去执行END中的语句
        akw 'BEGIn{i=1;do{print 1; exit;print 2}{print "fadsf"}END{print "over"}'
        1
        over
        
        # 跳过第二行
        awk '{if NR==2}{next}{print $0}' test6
        
    12:awk数组:awk中的数组默认下标从1开始
        awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; printhuluwa[1]}'
        如果我们直接引用这个不存在的元素,awk会自动创建这个元素,并且默认为这个元素赋值为"空字符串";所以在akw中我们不能是用if(huluwa[5]="")进行判断.一个
    元素是否为空,有可能它不存在,创建了一个.
        awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; printhuluwa[4]}'
        空
        
        如何进行判断呢?
        awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; if(6 in huluwa){print "6存在就打印出来"}}'
        
        # 使用!取反
        awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; if(!(6 in huluwa)){print "6存在就打印出来"}}'
        
        # 关联数组
        awk 'BEGIN{huluwa["一号"]="1";huluwa["二号"]="2";huluwa["三号"]="3" ; if(!("三号" in huluwa)){print "6存在就打印出来"}}'
        
        # delete删除数组
         awk 'BEGIN{huluwa["一号"]="1";huluwa["二号"]="2";huluwa["三号"]="3" ; print huluwa["一号"],delete huluwa;print huluwa["二号"]}'
         1
         空
         空 
         
       awk 'BEGIN{huluwa[0]="1";huluwa[1]="2";huluwa[2]="3" ; for(i=1;i<=3;i++){print i,huluwa[i]}}'
        1
        2
        3
        
        # 下表不规律的时候
        awk 'BEGIN{huluwa[0]="1";huluwa[8]="2";huluwa[11]="3" ; for(i in huluwa){print i,huluwa[i]}}'
        2
        3
        1
        注意:在这种语法中,for循环中的变量"i"表示的是元素的下标,而并非表示元素的值,所以,如果想要输出元素的值,则需要使用"print 数组名[变量]"
        注意:当数组中的下标为"字符串"时,元素值输出的顺序与元素在数组中的顺序不同,这是因为awk中的数组本质上是关联数组,所以默认打印出的元素是无序的。
        这就是以数字作为下标的优势,因为第一种for循环语法中的变量"i"为数字,由于for循环的原因,"i"是按照顺序递增的,当"i"的值与下标的值相同时,我们
    即可按照下标的顺序,输出对应元素的值,换句话说就是,我们是通过下标的顺序,输出对应元素值的顺序,也就是键值定位。但是,即使数组元素的下标为数字,如
    果使用第二种for循环语法,也不能够按照顺序输出,示例如下。
        awk 'BEGIN{huluwa[0]="1";huluwa[8]="2";huluwa[11]="3" ; for(i in huluwa){print i,huluwa[i]}}'
        2
        3
        1
        
        数值运算
        awk 'BEGIN{ a=1 ;print a; a++ ;print a}'
        1
        2
        awk 'BEGIN{ a="test" ;print a; a++ ;print a}'  # 将字符串当做0相加,空字符串也一样
        test
        1
        
        awk 'BEGIn{print array[x]; array[x]++;print array[x]}'
        空
        1
        
        cat test7
        18.43.31.4
        183.65.31.4
        18.22.31.4
        18.43.31.4
        
        awk '{count[$1]++} END{for (i in count){print i,count[i]}}' test7
        18.43.31.4 2
        183.65.31.4 1
        18.22.31.4 1
        
        cat -n test4
        allent phillips
        green lee
        william aiden james lee
        angle jack
        tyler kevin
        lucas thomas
        kevin
        
        awk '{for (i in NF){count[$i]++}} END{ for{j in count}{print j,count[j]}}' test4
        jack 1
        aiden 1
        james 1
        ..
        lee 2
        ..
        
    13.awk 内置函数
    	awk 'BEGIN{srand(); print rand()}'  # 生成随机数
        0.134324
        
        awk 'BEGIN{srand(); print int(rand()*100)}'  # 生成100以内的随机数
        0.134324
        
        cat test8
        allen fdsaf
        
        awk "{ gsub("l","L",$1); print $1 }" test8  # 全局字符替换,制定列的全部
        aLLen
        
        awk "{ sub("l","L",$1); print $1 }" test8  # 单字符替换,每一行中的第一匹配到的
        aLLen
        
        awk '{for(i=1;i<=NF;i++){print $i,length($i)}}' test8 # 输出字符串长度
        allen 5
        fdsaf 5
        
        awk '{for(i=1;i<=NF;i++){print $i,length()}}' test8 # 输出字符串长度,不指定列的时候,代表整行的长度
        allen fdsaf 12
       
    	cat test9
        allen phillips
        green lee
        william ken allen
        
        akw '{print index($0,"lee")}' test9
        0
        7
        0
        
        在每一行中咋找字符串"Lee",如果Lee存在于当前行,则返回字符串Lee位于当前行的位置,如果Lee不存在于当前行,则返回0,表示当前行并不存在Lee,如上图所示,
    第二行中包含Lee,而且Lee位于第二行的第7个字符的位置,所以返回数字7。
        
        awk -v ts="一号:二号:三号" 'BEGIN{split(ts,huluwa,":")for (i in huluwa){print huluwa[i]}}'  # 使用split生成数组
        一号
        二号
        三号
        
        被split函数分割后的数组的元素下标从1开始,不像其他语言中的数组下标是从0开始的,而且数组中元素输出的顺序可能与字符串中字符的顺序不同,
        
        awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8;for (i in t){print i, t[i]}}'
        a 66
        b 77
        c 8
        
        awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8;asort(t); for (i in t){print i, t[i]}}'
        1 3
        2 66
        3 77
        数组中元素的值均为数字,但是下标为自定义的字符串,通过asort函数对数组排序后,再次输出数组中的元素时,已经按照元素的值的大小进行了排序,但是,数组
    的下标也被重置为了纯数字,其实,asort还有一种用法,就是在对原数组元素值排序的同时,创建一个新的数组,将排序后的元素放置在新数组中,这样能够保持原数组不
    做任何改变,我们只要打印新数组中的元素值,即可输出排序后的元素值
        
        awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8;asort(t, newt); for (i in t){print i, t[i]}}'
        a 66
        b 77
        c 8 
        
        awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8;asort(t, newt); for (i in newt){print i, newt[i]}}'  # 生成新数组
        1 3
        2 66
        3 77
        
        awk 'BEGIN{t["a"]=66;t["b"]=77;t["c"]=8; len=asort(t, newt); for (i=1;i<=len;i++){print i, newt[i]}}'  # 生成新数组,asort的返回值是数组的长度
        1 3
        2 66
        3 77
        
        使用asort 函数可以根据元素的值进行排序,而使用asorti 函数可以根据元素的下标进行排序。
         awk 'BEGIN{t["f"]=66;t["b"]=77;t["e"]=8; len=asorti(t, newt); for (i=1;i<=len;i++){print i,newt[i]}}'
        1 b
        2 e
        3 f 
        当数组的下标为字符串时,asorti 函数会根据原数组中的下标的字母顺序进行排序,并且将排序后的下标放置到一个新的数组中,并且asorti函数会返回新的数组的长度
       awk 'BEGIN{t["f"]=66;t["b"]=77;t["e"]=8; len=asorti(t, newt); for (i in newt){print i,newt[i],t[newt[i]]}}'
        1 b 77
        2 e 8
        3 f 66 
        
    14:awk三元运算符与打印奇偶行
        我们可以判断用户的UID是否小于500,如果用户的UID大于500,则用户为普通用户,如果用户的UID小于500,则用户为系统用户。
        awk -F: 'if {($3 < 500){print "系统用户"} else if ($3 > 500){print "普通用户"}}' /etc/passwd
        
        awk -F: 'BEGIN{usertype=$3>500?"普通用户":"系统用户"; print $1,usertype}' /etc/passwd   
        条件 ? 结果1 : 结果2
        
        awk -F : '{$3>500?a++;b++}END{ print a,b}' /etc/passwd
        42 7   # 统计普通用户和系统用户数量
        
        akw '1{print $0}' test3  == awk '1' test3   # 其中的1可以理解为一种模式,1表示为真
        1 hey
        2 heey
        3 heeey
        
        akw '0{print $0}' test3  == awk '0' test3   # 其中的0可以理解为一种模式,0表示为假,所以不输出匹配的东西
        
        akw '!0{print $0}' test3  == awk '!0' test3   # 其中的0可以理解为一种模式,0表示为假,所以不输出匹配的东西,但是!表示取反,所以这个时候!0为真
    	1 hey
        2 heey
        3 heeey
        
        awk 'i=!i' test3    # 指数出奇数行,第一i为空(假),取反之后为真,第二次i真,取反之后为假,以此类推,第三次i为第二次的假,取反之后为真
        2 heey
    

    1.cpu:

    内置变量:
        $0 表示显示整行 
        $NF表示当前行分割后的最后一列($0和$NF均为内置变量),NF表示有多少列,$NF表示最后一列,进行运算$(NF-1)倒数第二列
    

    参考:
    http://www.zsythink.net/?s=awk
    https://blog.51cto.com/12758568/2122677
    https://blog.csdn.net/rj042/article/details/72860177 awk引用外部变量

  • 相关阅读:
    静态变量的问题
    水晶报表动态表数据显示的问题
    USACO Section 1.1 : Friday the Thirteenth
    USACO Section 1.2 : Transformations
    USACO Section 1.1 : Programming Contest Problem Types
    USACO Section 1.2 : Milking Cows
    USACO Section 1.1 : Greedy Gift Givers
    USACO Section 1.1 : Your Ride Is Here
    USACO Section 1.1 : Broken Necklace
    舍入Table.TransformColumns(Power Query 之 M 语言)
  • 原文地址:https://www.cnblogs.com/liuzhanghao/p/12970697.html
Copyright © 2020-2023  润新知