码迷,mamicode.com
首页 > 其他好文 > 详细

awk详解

时间:2015-05-21 06:43:43      阅读:145      评论:0      收藏:0      [点我收藏+]

标签:linux   awk   

一、awk简介

   awk的意思是报告生成器,能根据输入信息,把信息格式化后显示,继而出现new awk(nawk)在windows上实现,gawk,awk实现在linux上。awk是一种编程语言,在linux/unix下对文本和数据进行处理,是一款强大编程工具。在命令行中使用,更多作为脚本来使用。

   awk处理文件和数据的方式:逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行操作。如果没有指定处理动作,则把匹配行打印,如果没有指定模式,则所有行都处理。gawk是awk的GNU版本。可通过命令ll `which awk`查看

   Linux文本处理三剑客:

    grep, egrep, fgrep: 文本过滤器

    sed: 文本编辑(行编辑器) 

    awk: 文本格式化,报表生成器   

 awk工作过程

   根据定义的模式,一次从文本中读取一行,awk会对行做相应的切片,将每一行按照分割符进行切割。例如this is a test 使用空白字符做分隔符将它们分开,切割为this,is,a,test四个片,可以使用变量,分别对应为$1,$2,$3,$4代表四个切割片  

二、awk用法 

 1、基本格式 

   gawk [options] ‘program‘ file file ...

        program程序: PATTERN { ACTION STATEMENT }

          由语句组成,语句分隔符是";"          

        ACTION: print, printf 

    选项options:

      -F[]:指明输入字段分隔符;默认以空白为分隔符

          -F[, ]:逗号或空格为分隔符

      -v var=val: 变量赋值,无须声明,可直接调用

      -f /path/from/awk_script

  EX: 

   (1)、打印/etc/passwd中的第三行和第六行不同用法

    #awk -F: ‘{print $3,$6}‘ /etc/passwd 
    #awk -F: -v f1=3 -v f2=6 ‘{print $f1,$f2}‘ /etc/passwd  
    #awk -v FS=‘:‘ ‘{print $3,$6}‘ /etc/passwd

   (2)、运行awk脚本  

    #vim awk.script
     {print $1,$3}
    #awk -f awk.script -F: /etc/passwd

 2、awk的输出命令print    

    print item1, item2, ...

      item:

       (1)字符串:用引导引用

          print "htello","world"

       (2)变量:显示变量的值

          print name

     要点:

        (1)item间用逗号,输出为空白字符

        (2)item可以为字符串、变量、数值等

        (3)item如果省略,等于print $0

        (4)输出空白字符,print ""

    EX:打印/etc/passwd中的所有用户   

    #awk -F: ‘{print  "user is",$1}‘ /etc/passwd

 3、变量      

  3.1 内置变量

  (1)FS: input field seperator,输入字段分隔符,默认为空白字符;

    #awk -v FS=":" ‘{print $1,$3}‘ /etc/passwd
    #vim awk.txt
    This is the first line.
    Here you are.
    This is tomas,jason.
    #awk ‘{print $3}‘ awk.txt
    #awk -v FS="[ ,]" ‘{print $3}‘ awk.txt  //输出以逗号或空白字符为分隔符的字段

  (2)RS:input record separator,输入行分隔符 默认为换行符; 

  #awk -v RS=" " ‘{print $0}‘ /etc/passwd

  (3)OFS: output field separator,输出字段分隔符,默认为空白字符;  

 #awk -v FS=":" -v OFS=":" ‘{print $1,$3,$7}‘ /etc/passwd  //输出字段分隔符也为":"

  (4)ORS:output record separator,输出行分隔符, 默认为换行符;

  #awk -v RS=" " -v ORS=" " ‘{print $0}‘ /etc/passwd

  (5)NF: number of field in current  record,当前行的字段数;

  #awk ‘{print NF}‘ /etc/issue  //打印行数
  #awk ‘{print $NF}‘ /etc/issue  //打印行最后字段

  (6)NR:行数,所有文件统一计数;   

 #awk ‘{print NR}‘ /etc/issue

  (7)FNR:行数,各文件分别计数;  

 #awk ‘{print FNR}‘ /etc/fstab /etc/issue

  (8)FILENAME:当前被读取的文件名   

 #awk ‘{print NR,FILENAME}‘ /etc/issue

  (9)ARGC:命令行参数的个数;   

#awk ‘{print ARGC}‘ /etc/issue   //这里显示为两个参数,包括print和文件名

  (10)ARGV:数组,保存了命令行参数自身 

 #awk ‘{print ARGV[0]}‘ /etc/issue  //参数为print和文件名,但是输出ARGV[0],则显示为awk

 3.2 自定义变量

  -v var=val: 

    变量名命名规则:

      区分字符大小写

      数字,字符,下划线,不能以数字开头

      不能使用内置关键字   

    定义变量的位置:

      (1) 可以program中定义变量;

      (2) 通过-v选项定义变量;

    #awk ‘BEGIN{FS=":";f1=1}{print $f1}‘ /etc/passwd  //只在开始赋值一次     
    #awk -F: ‘{f1=1;print $f1}‘ /etc/passwd  //每行都要赋值

4、printf命令      

    格式: printf format, item1, item2, ...

    (1)要点:

        (1) format是必须的;

        (2) 不自动换行,需给换行符;\n

        (3) 为每个item指定格式符;否则item无法显示        

    (2)格式符:都以%开头,后跟一个字符

        %c: 显示字符的ASCII码;

        %d,%i: 显示十进制整数;

        %e, %E: 科学计数法显示数值;

        %f: 显示为浮点数;

        %g, %G: 以科学计数法格式或浮点数格式显示数值;

        %s: 字符串

        %u: 无符号的整数

        %%: 显示%自身  

 #awk -F: ‘{printf "This is user: %s.\n",$1}‘ /etc/passwd   
 #awk -F: ‘{printf "This is user: %s,his UID is %d.\n",$1,$3}‘ /etc/passwd

    (3)修饰符:

        #[.#]: 第一个#指定显示宽度,例如%30s;第二个#表示小数点后的精度;

        -: 左对齐,默认为右对齐

        +:显示数值符号

 #awk -F: ‘{printf "This is user: %s,his UID is %-20f.\n",$1,$3}‘ /etc/passwd  //UID显示为20个字符并且精度为2  
 #awk -F: ‘{printf "%20s:%-d\n",$1,$3}‘ /etc/passwd

 5、操作符:

  (1)算术操作符:

    x+y, x-y, x*y, x/y, x^y, x%y

    -x: 负值

    +x: 转换为数值

    #awk ‘BEGIN{print 4*5}‘ 

  (2)字符串操作:字符串连接

    #awk ‘BEGIN{print "hello" "awk"}’

  (3)赋值操作符:

     =, +=, -=, *=,  /=,  %=, ^=

     ++, --

  #awk -v f1=3 ‘BEGIN{f1*=6;print f1}‘

  (4)比较操作符:

     >, >=, <. <=, ==, !=       

  (5)模式匹配符:

     ~:能匹配为真

     !~:不能匹配为真       

  (6)逻辑操作符:

     && 与运算

     || 或运算       

  (7)条件表达式:

  selector?if-true-expression:if-false-expression

    相当于bash的:

     if SELECTOR;then

        if-true-expression

      else

        if-false-expression

  # awk -F: ‘{$3>=500?usertype="common user":usertype="sysuser or admin";printf "%20s:%-s\n",$1,usertype}‘ /etc/passwd
  #df -h | awk ‘{printf "%30s:%-s\n",$1,$5}‘

  (8)函数调用:

    function_name(argu1,argu2,...)        

 6、PATTERN     

    (1) /regular expression/: 正则表达式,仅处理能够被/regular expression/所匹配到的行;   

 #awk -F: ‘/^[ab]/{print $1,$3}‘ /etc/passwd

    (2) relational expression:关系表达式,有真假之分,一般来说,其结果为非0或非空字符串时为“真”,否则,为“假”;   

#awk -F: ‘$3>=500{print $1,$3}‘ /etc/passwd  //打印UID大于和等于500的用户名和UID
#awk -F: ‘$1~/root/{print $1,$3}‘  /etc/passwd   //打印用户名包含root的用户名和UID

    (3) line ranges:行范围,类似sed或vim的地址定界法;startline, endline

    (4) BEGIN/END: 特殊模式

    BEGIN:程序执行前执行一次

    END:程序执行后执行一次  

 #awk -F: ‘BEGIN{printf "%20s:%-s\n","UserName","UserID"}{printf "%20s:%-d\n",$1,$3}END{print "--------\nprogram is end"}‘  /etc/passwd  
 #awk ‘BEGIN{FS=":"}{print $1,$3}‘ /etc/passwd

    (5) empty: 空模式,匹配任意行;   

 #awk -F: ‘{print $1,$NF}‘ /etc/passwd

  7、常用的action     

    (1) Expressions  表达式,如变量赋值

    (2) Control statements  控制语句,如if,while等

    (3) Compound statements  复合语句,如{}

    (4) input statements  输入语句

    (5) output statements  输出语句   

  8、控制语句     

    if (condition条件) { statement语句 } [ else statement ]

    while (condition) { statement }

    do statement while (condition)

    for (expr1初值; expr2循环; expr3修正) statement

    for (var in array) statement

    switch (expression) {case VALUE or /REGEXP/:statement;...;default;statement}

    break  结束循环

    continue  结束本轮循环

    delete array[index]

    delete array

    exit [ expression ]

    { statements }     

  8.1 if-else        

     语法:if (condition条件) statement [ else statement ] 

           if (condition) { statements; } [ else { statements; }]               

 # awk -F: ‘{if ($3>=500) print $1," is a common user." }‘ /etc/passwd
 # awk -F: ‘{if ($3>=500) {print $1," is a common user."} else {print $1," is a system user or admin."}}‘ /etc/passwd
 # awk ‘{if (NF>6) print NF, $0 }‘ /etc/inittab

   用法:对awk取得的整行或行中的字段做条件判断;       

  8.2 while循环

   语法:while (condition) statement

        while (condition) { statements }

        条件为真时进行循环,直到为假退出;          

      用法:通常用于在当前行的各字段间进行循环;             

 # awk ‘{i=1;while(i<=NF){printf "%20s:%d\n",$i,length($i); i++}}‘ /etc/inittab   //打印每行字段名称和字段长度
 # awk ‘{i=1;while(i<=NF){if (length($i)>5) {printf "%20s:%d\n",$i,length($i);} i++}}‘ /etc/inittab  //查找打印在文件/etc/inittab下每行字段长度大于5的字段名称和长度

  8.3 do-while循环  了解

      语法:do statement while (condition)

        do { do-while-body }  while (condition)

        意义:至少执行一次循环体;        

  8.4 for循环

    语法:for (expr1; expr2; expr3) statement

      for (expr1; expr2; expr3) { statements }          

      for (varaiable assignment; condition; iteration process) { for-body }    

#awk ‘{for(i=1;i<=NF;i++){if(length($i)>=6) print $i}}‘ /etc/issue  //查找文件/etc/issue字段长度大于等于6并打印字段
#awk ‘{for(i=1;i<=NF;i++) {printf "%s:%d\n", $i, length($i)}}‘ /etc/inittab

    for循环在awk中有一个专用于遍历数组元素:

      语法:for (var in array) { for-body }          

  8.5 switch 了解

      语法:switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}          

  8.6 break and continue

        break [n]: 退出当前循环,n表示几层循环

        continue:提前结束本轮循环,直接进入下轮循环       

  8.7 next

       提前结束对本行的处理而进入下一行的处理               

 # awk -F: ‘{if($3%2==0) next;print $1,$3}‘ /etc/passwd   //打印UID为奇数的行的1和3字段,对UID取模,如果等于0则执行next进入对下一行的处理,如果不等于0则执行一条语句打印$1和$3字段

 9、Array 数组     

    关联数组:array[index-expression]     

      index-expression: 索引表达式

        可以使用任意字符串;

        如果某数组元素事先不存在,在引用时,awk会自动创建此元素并将其值初始化为空串;

           因此,若要判断数组是否存在某元素,要使用“index in array”进行;     

      要遍历数组中的每个元素,要使用: for (var in array) ,var会遍历array的每个索引,所以,要显示数组元素的值,要使用array[var]

     weekdays

        weekdays[mon]="Monday"

        weekdays[tue]="tuesday"

        ...

      for(i in weekdays) 此时i会遍历weekdays数组的每个索引,即mon,tue,而非元素的值"Monday"或"Tuesday"等

      要获取元素的值:weekdays[i]             

   EX:统计每一行中各单词分别出现的次数

      可定义一个数组,用单词本身当索引,而元素的值存储单词出现的次数     

# awk ‘{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]}}‘ awk.txt  //统计文本中每个单词及出现的次数,第一个for定义数组,第二个for遍历数组
# awk ‘{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]};delete count}‘ awk.txt //分别统计每行每个单词及出现的次数         
# ss -tan | awk ‘!/^State/{state[$1]++}END{for (i in state) {print i,state[i]}}‘   //统计TCP连接各状态名称及个数
#awk ‘{ip[$1]++}END{for(i in ip)print i,ip[i]}‘ /var/log/httpd/access_log  //统计web被访问的IP及次数
# netstat -tan | awk ‘/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}

 10、函数      

  (1)内置函数

    1)数值处理:

        rand(): 返回0和1之间一个随机数;    

#awk ‘BEGIN{print rand()}‘

    2)字符串处理:

        ength([s]): 返回指定字符串的长度  

#awk ‘BEGIN{print length("hello")}‘

    3)sub(r, s [, t])查找r在t中,把每行第一次出现的r替换为s

        sub(ab,AB,$0)    

#vim count.txt
How are you? How old are you?
#awk ‘{sub("are","ARE",$0);print $0}‘ count.txt

    4)gsub(r, s [, t]):查找r在t中,把所有出现的r替换为s

    5)split(s, a [, r]): 以r为分隔符,s为字符串切割,并把结果保存到a中

      注意:awk的数组下标从1开始编号     

#awk ‘{split($0,userinfo,":");print userinfo[1]}‘ /etc/passwd   //以":"为分隔符,$0为字符串切割,并把结果保存到userinfo中         
# netstat -tan | awk ‘/^tcp/{len=split($5,client,":");ip[client[len-1]]++}END{for(i in ip){print i,ip[i]}}‘

    6)substr(s, i [, n]): 从s表示的字符串中取子串,从i开始,取n个字符;        

    7)时间类的函数:

        systime(): 取时间戳;       

    8)位运算函数:

        and(v1,va2):          

  (2)自定义函数

        function f_name(p,q) 

        {

          ...

        }



本文出自 “蜗牛” 博客,请务必保留此出处http://linuxkingdom.blog.51cto.com/6334977/1653376

awk详解

标签:linux   awk   

原文地址:http://linuxkingdom.blog.51cto.com/6334977/1653376

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!