zoukankan      html  css  js  c++  java
  • awk

    awk

    目录

    1.awk介绍
    2.awk基本用法和工作原理
    3.awk的运用说明

    1.awk介绍

    awk是一种报表生成器,就是对文件进行格式化处理的,这里的格式化不是文件系统的格式化,而是对文件内容进行各种“排版”,进而格式化显示。
    在linux之上我们使用的是GNU awk简称gawk,并且gawk其实就是awk的链接文件,因此在系统上使用awk和gawk是一样。
    通过man awk可以取得相关功能说明,还可以知道,gawk是一种过程式编程语言,支持条件判断、数组、循环等各种编程语言中所有可以使用的功能,因此我们还可以把awk称为一种脚本语言解释器。

    2.awk基本用法和工作原理

    gawk - pattern scanning and processing language:(模式扫描和处理语言)

    基本用法:

    格式1:awk [options] -f progfile [--] file ...
    格式2:awk [options] [--] 'program' file ...
    格式3awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file ...
    -f progfile,--file=progfile:从文件中来读取awk 的program
    -F fs,--field-separator=fs:指明输入时用到的字段分割符
    -v var=val,--assign=var=val:在执行program之前来定义变量
    program:相当于编程语言,也就是处理后面文件的一系列操作语句
    progfile:带有program或BEGIN等操作语句内容的文件
    BEGIN:读取输入流前进行操作的标志
    END:输入流读取完后进行操作的标志
    pattern:模式,对输入流进行操作,实际上paogram就代表这pattern部分
    action:动作语言,由多种语句组成,语句间用分号分割

    工作原理:
    从上面可以看到看似有三个格式,实际上总的来说就一个格式,就是格式3,因为格式1和2展开后,也就是格式3。

    格式:awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file ...

    第一步:执行[option]相关内容,也就是-f,-F,-v选项内容。
    第二步:执行BEGIN{action;… } 语句块中的语句。BEGIN 语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN 语句块中。
    第三步:从文件或标准输入(stdin) 读取每一行,然后执行pattern{action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern 语句块,则默认执行{ print } ,即打印每一个读取到的行,awk 读取的每一行都会执行该语句块。
    第四步:当读至输入流末尾时,也就是所有行都被读取完执行完后,再执行END{action;…} 语句块。END 语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END 语句块中完成,它也是一个可选语句块。

    3.awk的运用

    1.awk中的变量

    变量分为内置变量和自定义变量,但只要是变量都是用的选项-v。先选常用的内置变量说明下,然后说下自定义的变量。
    内置变量:

    FS:输入字段分隔符,默认为空白字符,这个想当于-F选项。分隔符可以是多个,用[]括起来表示,如:-v FS="[,./-:;]"
    OFS:输出字段分隔符,默认为空白字符,分隔符可以是多个,同上
    RS :输入记录(所认为的行)分隔符,指定输入时的换行符,原换行符仍有效,分隔符可以是多个,同上
    ORS :输出记录(所认为的行)分隔符,输出时用指定符号代替换行符,分隔符可以是多个,同上
    NF :字段数量
    NR :记录数(所认为的行)
    FNR :各文件分别计数, 记录数(行号)
    FILENAME :当前文件名
    ARGC:命令行参数的个数
    ARGV :数组,保存的是命令行所给定的各参数

    自定义变量(区分字符大小写):

    在'{...}'前,需要用-v var=value:awk -v var=value '{...}'
    在program 中直接定义:awk '{var=vlue}'

    下面针对每个变量都举个例子:

    awk -v FS=':' '{print $1,FS,$3}’ /etc/passwd
    awk –F: '{print $1,$3,$7}’ /etc/passwd
    awk -v FS=‘:’ -v OFS=‘:’ '{print $1,$3,$7}’ /etc/passwd
    awk -v RS=' ' ‘{print }’ /etc/passwd
    awk -v RS="[[:space:]/=]" '{print }' /etc/fstab |sort
    awk -v RS=' ' -v ORS='###'‘{print }’ /etc/passwd
    awk -F: ‘{print NF}’ /etc/fstab, 引用内置变量不用$
    awk -F: '{print $(NF-1)}' /etc/passwd
    awk '{print NR}' /etc/fstab ; awk 'END{print NR}' /etc/fstab
    awk '{print FNR}' /etc/fstab /etc/inittab
    awk '{print FNR}' /etc/fstab /etc/inittab
    awk '{print FILENAME}’ /etc/fstab
    awk '{print ARGC}’ /etc/fstab /etc/inittab
    awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
    awk ‘BEGIN {print ARGV[0]}’ /etc/fstab   /etc/inittab
    awk ‘BEGIN {print ARGV[1]}’ /etc/fstab  /etc/inittab
    awk -v test='hello gawk' '{print test}' /etc/fstab
    awk -v test='hello gawk' 'BEGIN{print test}'
    awk 'BEGIN{test="hello,gawk";print test}'
    awk –F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd
    awk -F: '{sex="male";age=18;print $1,sex,age}' /etc/passwd
    echo "{print script,$1,$2}"  > awkscript
    awk -F: -f awkscript script=“awk” /etc/passwd
    

    2.awk的print和printf

    print和printf都是打印输出的,不过两者用法和显示上有些不同而已。

    print 格式:print item1,item2, ...
    printf格式:printf “FORMAT ”,item1,item2, ...

    要点
    1.逗号为分隔符时,显示的是空格;
    2.分隔符分隔的字段(域)标记称为域标识,用$0,$1,(2,...,)n表示,其中$0 为所有域,$1就是表示第一个字段(域),以此类推;
    3.输出的各item可以字符串,也可以是数值,当前记录的字段,变量或awk 的表达式等;
    4.如果省略了item ,相当于print $0
    5.对于printf来说,必须指定FORMAT,即必须指出后面每个itemsN的输出格式,且还不会自动换行,需要显式则指明换行控制符" "

    printf的格式符和修饰符

    %c:显示字符的ASCII码
    %d, %i:显示十进制整数
    %e, %E:显示科学计数法数值
    %f:显示为浮点数
    %g, %G:以科学计数法或浮点形式显示数值
    %s:显示字符串
    %u:无符号整数
    %%:显示%自身
    #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f
    -:左对齐(默认右对齐);%-15s,就是以左对齐方式显示15个字符长度
    +:显示数值的正负符号 %+d

    这里也举个示例:

    awk '{print "hello,awk"}'
    awk –F: '{print}' /etc/passwd
    awk –F: ‘{print “wang”}’ /etc/passwd
    awk –F: ‘{print $1}’ /etc/passwd
    awk –F: ‘{print $0}’ /etc/passwd
    awk –F: ‘{print $1”	”$3}’ /etc/passwd
    tail –3 /etc/fstab |awk ‘{print $2,$4}’
    awk -F: ‘{printf "%s",$1}’ /etc/passwd
    awk -F: ‘{printf "%s
    ",$1}’ /etc/passwd
    awk -F: '{printf "%-20s %10d
    ",$1,$3}' /etc/passwd
    awk -F: ‘{printf "Username: %s
    ",$1}’ /etc/passwd
    awk -F: ‘{printf “Username: %s,UID:%d
    ",$1,$3}’ /etc/passwd
    awk -F: ‘{printf "Username: %15s,UID:%d
    ",$1,$3}’ /etc/passwd
    awk -F: ‘{printf "Username: %-15s,UID:%d
    ",$1,$3}’ /etc/passwd
    lsmod
    awk -v FS=" " 'BEGIN{printf "%s %26s %10s
    ","Module","Size","Used by"}{printf "%-20s %13d %5s %s
    ",$1,$2,$3,$4}' /proc/modules
    

    3.awk的操作符

    算术操作符:x+y, x-y, x*y, x/y, x^y, x%y
    赋值操作符:=, +=, -=, *=, /=, %=, ^=,++, --
    比较操作符:==, !=, >, >=, <, <=
    模式匹配符:~ :左边是否和右边匹配包含;!~ :是否不匹配
    逻辑操作符:与:&& ;或:|| ;非:!
    条件表达式(三目表达式):selector ? if-true-expression : if-false-expression

    示例:

    awk –F: '$0 ~ /root/{print $1}‘ /etc/passwd
    awk '$0~“^root"' /etc/passwd
    awk '$0 !~ /root/‘ /etc/passwd
    awk –F: ‘$3==0’ /etc/passwd
    awk–F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
    awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
    awk -F: ‘!($3==0) {print $1}' /etc/passwd
    awk -F: ‘!($3>=500) {print $3}’ /etc/passwd
    awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%15s:%-s
    ",$1,usertype}' /etc/passwd
    

    4.awk的pattern

    awk语句中是根据pattern条件,过滤匹配的行,再做处理。
    1.未指定:表示空模式,匹配每一行
    2./regular expression/:仅处理能够模式匹配到的行,支持正则表达式,需要用/ /括起来
    3.关系表达式:结果为“真”才会被处理。真:结果为非0值,非空字符串。假:结果为空字符串或0值
    4./pat1/,/pat2/:startline,endline ,行范围,支持正则表达式,不支持直接给出数字格式
    5.BEGIN{}和END{}BEGIN{} 仅在开始处理文件中的文本之前执行一次。END{}仅在文本处理完成之后执行 一次

    示例:

    awk '/^UUID/{print $1}' /etc/fstab
    awk '!/^UUID/{print $1}' /etc/fstab
    awk -F: ‘/^root>/,/^nobody>/{print $1}' /etc/passwd
    awk -F: ‘(NR>=10&&NR<=20){print NR,$1}'  /etc/passw
    awk -F: 'i=1;j=1{print i,j}' /etc/passwd
    awk ‘!0’ /etc/passwd ; awk ‘!1’ /etc/passwd
    awk –F: '$3>=1000{print $1,$3}' /etc/passwd
    awk -F: '$3<1000{print $1,$3}' /etc/passwd
    awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
    awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
    awk -F : 'BEGIN {print "USER USERID"} {print $1":"$3}END{print "end file"}' /etc/passwd
    awk -F: 'BEGIN{print "    USER     USERID"}{printf "|%8s| %10d|
    ",$1,$3}END{print "END FILE"}' /etc/passwd
    awk -F : '{print "USER USERID“;print $1":"$3} END{print"end file"}' /etc/passwd
    awk -F: 'BEGIN{print " USER UID 
    ---------------"}{print $1,$3}' /etc/passwd
    awk -F: 'BEGIN{print "    USER     USERID
    ----------------------"}{printf "|%8s| %10d|
    ",$1,$3}END{print "----------------------
    END FILE"}' /etc/passwd
    awk -F: 'BEGIN{print " USER UID 
    ---------------"}{print $1,$3}'END{print "=============="} /etc/passwd
    seq 10 |awk ‘i=0’
    seq 10 |awk ‘i=1’
    seq 10 | awk 'i=!i‘
    seq 10 | awk '{i=!i;print i}‘
    seq 10 | awk ‘!(i=!i)’
    seq 10 |awk -v i=1 'i=!i'
    

    5.awk的action

    awk中的action可以分为以下5类:
    1.表达式语句,包括算术表达式和比较表达式,就是用进行比较和计算的。
    2.控制语句,用作进行控制,典型的就是if else,while等语句,和bash脚本里面用法差不多。
    3.输入语句,用来做为输入,变量赋值就算是。
    4.输出语句,用来输出显示的,典型的是print和printf
    5.组合语句,这个很多理解,就是多种语句的组合

    下面就具体说下一些语句的具体内容,也没有分割那么清晰,但都属于action范围:

    1.awk的if-else

    语法:

    {if(condition){statement;…}}:条件满足就执行statement
    {if(condition){statement1;…}{else statement2}}:条件满足执行statement1,不满足执行statement2
    {if(condition1){statement1}else if(condition2){statement2}else{statement3}}:条件1满足执行statement2,不满足条件1但满足条件2执行statement2,所用条件都不满足就执行statement3

    示例:

    awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd
    awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
    awk '{if(NF>5) print $0}' /etc/fstab
    awk -F: '{if($3>=1000) {printf "Common user: %s
    ",$1}else{printf "root or Sysuser: %s
    ",$1}}' /etc/passwd
    awk -F: '{if($3>=1000) printf "Common user: %s
    ",$1;else printf "root or Sysuser: %s
    ",$1}' /etc/passwd
    df -h|awk -F% '/^/dev/{print $1}'|awk '$NF>=80{print $1,$5}‘
    awk 'BEGIN{ test=100;if(test>90){print "very good"}else if(test>60){ print "good"}else{print "no pass"}}'
    
    2.awk的while和do-while

    语法:

    while(condition){statement;…}:条件为“真”时,进入循环;条件为“假”时, 退出循环
    do {statement;…}while(condition):无论真假,至少执行一次循环体。当条件为“真”时,退出循环;条件为“假”时,继续循环

    示例:

    awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i); i++}}' /etc/grub2.cfg
    awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=10){print $i,length($i)}; i++}}' /etc/grub2.cfg
    awk 'BEGIN{ total=0;i=0;do{total+=i;i++}while(i<=100);print total}‘
    
    3.awk的for

    语法:

    for(expr1;expr2;expr3) {statement;…}:expr1为变量赋值,如var=value,初始进行变量赋值;expr2为条件判断语句,j<=10,满足条件就继续执行statement;expr3为迭代语句,如j++,每次执行完statement后就迭代增加
    for(var in array) {for-body}:变量var遍历数组,每个数组中的var都会执行一次for-body

    示例:

    awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
    awk '/^[^#]/{type[$3]++}END{for(i in type)print i,type[i]}' /etc/fstab
    awk -v RS="[[:space:]/=,-]" '/[[:alpha:]]/{ha[$0]++}END{for(i in ha)print i,ha[i]}' /etc/fstab
    
    4.awk的switch

    switch 语句,相当于bash中的case语句。
    语法:

    switch(expr) {case VAL1 or /REGEXP/:statement1; case VAL2 or /REGEXP2/: statement2;...; default: statementn}:若expr满足 VAL1 or /REGEXP/就执行statement1,若expr满足VAL2 or /REGEXP2/就执行statement2,以此类推,执行statementN,都不满足就执行statement

    5.awk的break、continue和next

    break 和continue,用于条件判断循环语句,next是用于awk自身循环的语句。

    break[n]:当第n次循环到来后,结束整个循环,n=0就是指本次循环
    continue[n]:满足条件后,直接进行第n次循环,本次循环不在进行,n=0也就是提前结束本次循环而直接进入下一轮
    next:提前结束对本行的处理动作而直接进入下一行处理

    示例:

    awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}‘
    awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}‘
    awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
    
    6.awk的数组

    awk的数组是关联数组,格式为:

    array[index-expression]:arry为数组名,index-expression为下标。

    实际上index-expression可使用任意字符串,字符串要使用双引号括起来;如果某数组元素事先不存在,在引用时,awk 会自动创建此元素,并将其值初始化为“空串”。
    若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历。
    若要遍历数组中的每个元素,要使用for循环:for(var in array) {for-body},使用for循环会使var 会遍历array的每个索引。此时要显示数组元素的值,则要使用array[var]。
    示例:

    awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}‘
    awk '!arr[$0]++' dupfile
    awk '{!arr[$0]++;print $0, arr[$0]}' dupfile
    awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}‘
    netstat -tan | awk '/^tcp/{state[$NF]++}END{for(i in state) { print i,state[i]}}'
    awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}'/var/log/httpd/access_log
    
    7.awk的函数

    awk的函数有许多,除了系统自带的内建函数还有就是用户自定义的函数,这里挑选几个常用的函数。

    rand():返回0 和1 之间一个随机数
    srand():生成随机数种子
    int():取整数
    length([s]):返回指定字符串的长度
    sub(r,s,[t]):对t字符串进行搜索,r表示的模式匹配的内容,并将第一个匹配的内容替换为s
    gsub(r,s,[t]):对t字符串进行搜索,r表示的模式匹配的内容,并全部替换为s 所表示的内容
    split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array 所表示的数组中,第一个索引值为1, 第二个索引值为2,…也就是说awk的数组下标是从1开始编号的。
    substr(s,i,[n]):从s所表示的字符串中取子串,取法:从i表示的位置开始,取n个字符。
    systime():取当前系统时间,结果形式为时间戳。
    system():调用shell中的命令。空格是awk中的字符串连接符,如果system 中需要使用awk中的变量可以使用空格分隔,或者说除了awk的变量外其他一律用"" 引用 起来。

    示例:

    awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
    echo "2008:08:08 08:08:08" | awk 'sub(/:/,“-",$1)'
    echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,“-",$0)'
    netstat -tan | awk '/^tcp>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
    awk BEGIN'{system("hostname") }'
    awk 'BEGIN{score=100; system("echo your score is " score) }'
    

    自定义函数,格式为

    function fname ( arg1,arg2 , ... ) {
    statements
    return expr
    }
    

    自定义函数中fname为函数名,arg1...为函数的参数,statements是动作语言,return expr为由statements的结果从而决定最终函数所显示的内容。
    示例:

    cat fun.awk
    	function max(v1,v2) {
    	    v1>v2?var=v1:var=v2
    	    return var
    	}
          BEGIN{a=3;b=2;print max(a,b)}
    awk –f fun.awk
    

    6.awk的脚本

    awk的脚本就是将awk程序写成脚本形式,来直接调用或直接执行。例如上面写自定义函数的样子也算是脚本。

    格式1:
    BEGIN{} pattern{} END{}
    格式2:
    #!/bin/awk  -f
    #add 'x'  right 
    BEGIN{} pattern{} END{}
    

    格式1假设为f1.awk文件,格式2假设为f2.awk文件,那么用法是:

    awk [-v var=value] f1.awk [file]
    f2.awk [-v var=value] [var1=value1] [file]

    对于awk [-v var=value] f1.awk [file]来说,很好理解,就是把处理阶段放到一个文件而已,真正展开后,也就是普通的awk语句。
    对于f2.awk [-v var=value] [var1=value1] [file]来说, [-v var=value] 是在BEGIN之前设置的变量值,[var1=value1]是在BEGIN过程之后进行的,也就是说直到首行输入完成后,这个变量才可用,这就想awk脚本黄总传递参数了。
    示例:

    cat f1.awk
        {if($3>=1000)print $1,$3}
    awk -F: -f f1.awk /etc/passwd
    
    cat f2.awk
        #!/bin/awk –f
        #this is a awk script
        {if($3>=1000)print $1,$3}
        #chmod +x f2.awk
    f2.awk –F: /etc/passwd
    
    cat test.awk
        #!/bin/awk –f
        {if($3 >=min && $3<=max)print $1,$3}
        #chmod +x test.awk
    test.awk -F: min=100 max=200 /etc/passwd
    

    到此为止算是差不多了,实际上awk的内容好多,这里只是写了所知道的,更详细的可看man awk来获取更加全面的知识。上述若有错误的地方,欢迎提出!谢谢~

  • 相关阅读:
    集合:HashMap原理
    监控管理
    jvm(内存分配和回收策略、字节码执行引擎、运行时栈的结构)
    jvm:收集器
    多线程(线程的四种创建方式)
    scrapy之下载器中间件(Download Middleware)
    scrapy之Spider
    Scrapy之原理&提取数据
    小程序之请求服务器资源注意问题
    小程序之页面跳转
  • 原文地址:https://www.cnblogs.com/shenxm/p/7616226.html
Copyright © 2011-2022 走看看