awk灵活运用

awk:报告生成器,格式化文本输出
        有多种版本:New awk (nawk ),GNU awk(gawk)
gawk:模式扫描和处理语言
基本用法:
awk [options] ‘program’ var=value file…
awk [options] -f programfile var=value file…
awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{action;… }’ file …
awk 程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成
program 通常是被单引号或双引号;尽量使用单引号
  选项:
       -F  指明输入时用到的字段分隔符
       -v  var=value: 

基本格式:awk [options] ‘program’ file…
   program:pattern{action statements;..}
   pattern 和action: :
• pattern 部分决定动作语句何时触发及触发事件BEGIN,END
• action statements 对数据进行处理,放在{} 内指明print, printf分割符、域和记录
• awk 执行时,由分隔符分隔的字段(域)标记$1,$2..$n称
  为域标识。$0 为所有域,注意:和shell 中变量$ 符含义不同
• 文件的每一行称为记录
• 省略action行 ,则默认执行 print $0的操作

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

 print 格式:print item1, item2, …
  要点:
• (1)  逗号分隔符
• (2)  输出的各item 可以字符串,也可以是数值;当前记录的字段、
变量或awk 的表达式
• (3)  如省略item ,相当于print $0
  示例:
awk ‘{print “hello,awk”}’  file
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”\t”$3}’ /etc/passwd
tail –3 /etc/fstab |awk ‘{print $2,$4}’

awk变量:内置和自定义变量
 FS :输入字段分隔符,默认为空白字符
      awk -v FS=’:’ ‘{print $1,FS,$3}’ /etc/passwd
      awk –F: ‘{print $1,$3,$7}’ /etc/passwd
 OFS :输出字段分隔符,默认为空白字符
      awk -v FS=‘:’ -v OFS=‘:’ ‘{print $1,$3,$7}’ /etc/passwd
 RS :输入记录分隔符,指定输入时的换行符,原换行符仍有效
      awk -v RS=’ ‘ ‘{print }’ /etc/passwd
 ORS :输出记录分隔符,输出时用指定符号代替换行符
      awk -v RS=’ ‘ -v ORS=’###’‘{print }’ /etc/passwd
 NF :字段数量
      awk -F:‘{print NF}’ /etc/fstab, 引用内置变量不用$
      awk -F: ‘{print $(NF-1)}’ /etc/passwd
 NR :行号
      awk ‘{print NR}’ /etc/fstab ; awk END'{print NR}’ /etc/fstab

FNR :各文件分别计数, 行号
    awk ‘{print FNR}’ /etc/fstab /etc/inittab
FILENAME :当前文件名
    awk ‘{print FILENAME}’ /etc/fstab
ARGC :命令行参数的个数
    awk ‘{print ARGC}’ /etc/fstab /etc/inittab
    awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
ARGV :数组,保存的是命令行所给定的各参数
      awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab
      awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab

printf命令:
格式化输出:printf  “FORMAT ”, item1, item2, …
(1)  必须指定FORMAT
(2)  不会自动换行,需要显式给出换行控制符,\n
(3)  FORMAT 中需要分别为后面每个item 指定格式符
     格式符:与item 一一对应
%c:  显示字符的ASCII码 码
%d, %i:  显示十进制整数
%e, %E: 显示科学计数法数值
%f :显示为浮点数
%g, %G :以科学计数法或浮点形式显示数值
%s :显示字符串
%u :无符号整数
%%:  显示% 自身
  修饰符:

[.#] :第一个数字控制显示的宽度;第二个# 表示小数点后精度,%3.1f

      –   :  左对齐(默认右对齐) %-15s                                           #加上负号表示左对齐
      +   :显示数值的正负符号 %+d
exam:
• awk -F: ‘{printf “%s”,$1}’ /etc/passwd
• awk -F: ‘{printf “%s\n”,$1}’ /etc/passwd
• awk -F: ‘{printf “%-20s %10d\n”,$1,$3}’ /etc/passwd
• awk -F: ‘{printf “Username: %s\n”,$1}’ /etc/passwd
• awk -F: ‘{printf “Username: %s,UID:%d\n”,$1,$3}’ /etc/passwd
• awk -F: ‘{printf “Username: %15s,UID:%d\n”,$1,$3}’ /etc/passwd
• awk -F: ‘{printf “Username: %-15s,UID:%d\n”,$1,$3}’ /etc/passwd

算术操作符:
x+y, x-y, xy, x/y, x^y, x%y
-x:  转换为负数
+x:  转换为数值
   字符串操作符:没有符号的操作符,字符串连接
   赋值操作符:
            =, +=, -=, *=, /=, %=, ^=
            ++, —
  比较操作符:
            ==, !=, >, >=, <, <=
  模式匹配符:~ :左边是否和右边匹配包含 !~ :是否不匹配
        awk –F: ‘$0 ~ /root/{print $1}‘ /etc/passwd    #整行包括root就打印
        awk ‘$0~“^root”‘ /etc/passwd                   #行首包含root
        awk ‘$0 !~ /root/‘ /etc/passwd
        awk –F: ‘$3==0’ /etc/passwd
        awk -F: ‘$3==1000{print $1,$3}’ /etc/passwd    #一个等号是赋值,2个比较

逻辑 操作符:与&& ,或|| ,非!  
   示例:
• 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      #取反需要小括号
  函数调用: function_name(argu1, argu2, …)
  条件表达式(三目表达式):
selector?if-true-expression:if-false-expression
      #为真就执行第一个命名,为假执行第二个命令
• 示例:
      awk -F: ‘{$3>=1000?usertype=”Common User”:usertype=”Sysadmin”;printf 
               “%15s:%-s\n”,$1,usertype}’ /etc/passwd

PATTERN: 根据pattern 条件,过滤匹配的行,再做处理
(1) 如果未指定:空模式,匹配每一行
(2) /regular expression/ :仅处理能够模式匹配到的行,需要用/ /括起来
      awk ‘/^UUID/{print $1}’ /etc/fstab
      awk ‘!/^UUID/{print $1}’ /etc/fstab
(3) relational expression:  关系表达式,结果为“真”才会被处理
    真:结果为非0 值,非空字符串          #“0”表示有字符串0,为真
    假:结果为空字符串或0值               #0为假 ,0以外的都是真
    示例:
• awk -F: ‘i=1;j=1{print i,j}’ /etc/passwd   #i=1;分号单独打印了,用,就代表一起
• 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/passw
(4) line ranges   : 行范围   也支持贪婪模式
    startline,endline :/pat1/,/pat2/  不支持直接给出数字格式
    awk -F: ‘/^root\>/,/^nobody\>/{print $1}’  /etc/passwd
    awk -F: ‘(NR>=10&&NR<=20){print NR,$1}’    /etc/passwd
(5) BEGIN/END 模式
      BEGIN{}:  仅在开始处理文件中的文本之前执行一次
      END{} :仅在文本处理完成之后执行一次
      seq 10|awk ‘i=!i’ :当i=1的时候打印第一行,循环到第二行时候1取反等于0
                          不打印第二行,第三行0取反为真,打印第三行,打印奇数行
      seq 10 |sed -n ‘1~2p’

awk控制语句:
 { statements;… }  组合语句
 if(condition) {statements;…}
 if(condition) {statements;…} else {statements;…}
 while(conditon) {statments;…}
 do {statements;…} while(condition)
 for(expr1;expr2;expr3) {statements;…}
 break
 continue
 delete array[index]
 delete array
 exit

语法:if(condition){statement;…}[else statement]
      if(condition1){statement1}else if(condition2){statement2}
      else{statement3}                #条件和语句一起使用,条件用()
    使用场景:对awk 取得的整行或某个字段做条件判断
    完整的语句之间使用不要用使用;号   {}中使用;号
    示例:
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\n”,$1} else
         {printf “root or Sysuser: %s\n”,$1}}’ /etc/passwd
awk -F: ‘{if($3>=1000) printf “Common user: %s\n”,$1;
         else printf “root or Sysuser: %s\n”,$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”}}’

while 循环
  语法:while(condition){statement;…}
  条件“真”,进入循环;条件“假”,退出循环
  使用场景:
        对一行内的多个字段逐一类似处理时使用
        对数组中的各元素逐一处理时使用
  示例:
      awk ‘/^[[:space:]]
linux16/{i=1;while(i<=NF)       #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
  length:统计有几个字符,awk自带的函数‘
      akw ‘BEGIN{print length(“aaaaaaaaa”)}’  #统计有几个a

do-while 循环
  语法:do {statement;…}while(condition)
  意义:无论真假,至少执行一次循环体                 #意思是先执行再循环
  示例:
• awk ‘BEGIN{ total=0;i=0;do{
      total+=i;i++;}while(i<=100);print total}‘
  思考:下面两语句有何不同?
• awk ‘BEGIN{i=0;print ++i,i}’          #先赋值,再打印
• awk ‘BEGIN{i=0;print i++,i}’          #先打印i 再赋值

 for 循环
  语法:for(expr1;expr2;expr3) {statement;…}
  常见用法:
for(variable assignment;condition;iteration process){for-body}
  特殊用法:能够遍历数组中的元素;
语法:for(var in array) {for-body}
  示例:
   awk ‘/^[[:space:]]
linux16/{for(i=1;i<=NF;i++) {print$i,length($i)}}’ 
                                                              /etc/grub2.cfg

1到100相加的几种方法:awk效率最高
 time (awk ‘BEGIN{
              total=0;for(i=0;i<=10000;i++){total+=i;};print total;}’)
 time(total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
 time(for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
 time(seq –s ”+” 10000|bc)           #-s指定分隔符,默认是换行

 switch 语句
  语法:switch(expression) {case VALUE1 or /REGEXP/:
      statement1; case VALUE2 or /REGEXP2/: statement2; …; default: statementn}
   break 和continue
• 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}‘
   break [n]
 continue [n]
 next:  提前结束对本行处理而直接进入下一行处理(awk 自身循环)
          awk -F: ‘{if($3%2!=0) next; print $1,$3}’ /etc/passwd

关联数组:array[index-expression]
          index-expression:
• (1) 可使用任意字符串;字符串要使用双引号括起来
• (2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,
      并将其值初始化为“空串”
•  若要判断数组中是否存在某元素,要使用“index in array”格 式进行遍历
   示例:
• weekdays[“mon”]=”Monday“
• awk ‘BEGIN{weekdays[“mon”]=”Monday”; 
       weekdays[“tue”]=”Tuesday”;print weekdays[“mon”]}‘
• awk ‘!arr[$0]++’ dupfile         #出现重复的$0 加1但是不再打印  和uniq -c 类似
• awk ‘{!arr[$0]++;print $0, arr[$0]}’ dupfile
  若要遍历数组中的每个元素,要使用for 循环
   for(var in array) {for-body}
   注意:var 会遍历array 的每个索引
   示例:
• 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

数值处理:
      rand() :返回0 和1 之间一个随机数
          awk ‘BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }’
字符串处理:
• length([s])  : 返回指定字符串的长度
• sub(r,s,[t]) : 对t 字符串进行搜索r 表示的模式匹配的内容,
                  并将第一个匹配的内容替换为s
          echo “2008:08:08 08:08:08” | awk ‘sub(/:/,“-“,$1)’
• gsub(r,s,[t]) :对t 字符串进行搜索r 表示的模式匹配的内容,并全部替换
                为s 所表示的内容
          echo “2008:08:08 08:08:08” | awk ‘gsub(/:/,“-“,$0)’
• split(s,array,[r]) :以r 为分隔符 ,切割字符串s ,并将切割后的结果保存
  至array所表示的 数组中,第一个索引值为1, 第二个索引值为2,…
          netstat -tan | awk ‘/^tcp\>/{split($5,ip,”:”);count[ip[1]]++}
          END{for (i in count) {print i,count[i]}}’

自定义函数
  格式:
function name ( parameter, parameter, … ) {
            statements
            return expression
}
  示例:

cat fun.awk

function max(v1,v2) {                  #函数名和参数(形参)
      v1>v2?var=v1:var=v2              #三目表达式
      return var                       #函数的值就是var
}
BEGIN{a=3;b=2;print max(a,b)}          #实参

awk –f fun.awk                        #-f 调用awk函数

system 命令               #awk中可以调用shell命令
  空格是awk 中的字符串连接符,如果system 中需要使用awk中
    的变量可以使用空格分隔,或者说除了awk 的变量外其他一律用”” 引用起来。
           awk BEGIN'{system(“hostname”) }’
           awk ‘BEGIN{score=100; system(“echo your score is ” score) }’

将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

格式:
  awkfile var=value var2=value2… Inputfile      #在脚本外面传递参数        
  注意 :在BEGIN 过程中不可用。直到首行输入完成以后,变量才可用。可以通过-v参数,
  让awk 在执行BEGIN 之前得到变量的值。命令行中每一个指定的变量都需要一个-v 参数
   示例:

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/passw    
      这里的赋值可以再print里面使用,再BEGIN和END里面需要-v min=200
      但是建议习惯使用-v不管如何都能使用,免得遗忘

原创文章,作者:shewei,如若转载,请注明出处:http://www.178linux.com/72763

(0)
sheweishewei
上一篇 2017-04-08
下一篇 2017-04-08

相关推荐

  • rpm包管理

    rpm包管理 由于 RPM 是透过预先编译打包成为 RPM 文件格式后,再加以安装的一种方式,还能够进行数据库的记载。 所以 RPM 有以下的优点: RPM 内含已经编译过的程序与配置文件等数据,可以让用户免除重新编译的困扰; RPM 在被安装前,会先检查系统的硬盘容量、操作系统版本等,可避免档案被错误安装; RPM 档案本身提供软件版本信息、相依属性软件名…

    Linux干货 2016-08-21
  • LVM逻辑卷管理器(Logical Volume Manager)

    逻辑卷管理器(Logical Volume Manager) 简介      LVM的做法是将几个物理的分区通过软件组合成为一块看起来是独立的大磁盘(VG),然后将这块大磁盘再分成可以使用的分区(LV),最终就能够挂载使用了。内部通过PE来进行扩展或缩小。 PV(PhysicalVolume)物理卷 用fdisk命令调整系统标识…

    Linux干货 2016-09-01
  • 计算机和linux基础

    计算机的组成及其功能 计算机硬件主要由5部分组成:运算器 、控制器、存储器、input、output。 但是这和我们平时见到的计算机不一样?我们平时见到的计算机有CPU,内存,硬盘,显示器,鼠标键盘,显卡、主板等。这些东西也都归在以上五类设备中。下面我们简单介绍一下计算机这五个组成部分。 运算器: 运算器是计算机中做运算的部分,可以执行各种指令,加减乘除,与…

    Linux干货 2016-09-16
  • 文本处理工具应用练习

    练习:  1 、找出ifconfig 命令结果中本机的IPv4 地址 思路:我们使用ifconfig命令可知,ip地址是在第二行,所以我们先筛选出第二行,       第二行中的分隔符看起来很混乱,都是不规则的,有一个空格或多个空格的,没有标准       所以我们最好是建立一个标准分隔,…

    Linux干货 2016-08-08
  • iptables 初识

    iptables 包过滤性防火墙     iptables是位于用户空间,是防火墙管理配置规则的工具。     iptables的作用:用来添加,删除,管理netfilter规则。     Netfilter是位于内核中真正的防火墙,由5个钩子组成,…

    Linux干货 2016-06-01
  • LVM2 逻辑卷管理工具

    LVM2:  LVM: Logical Volume Manager, Version: 2  dm: device mapper,将一个或多个底层块设备组织成一个逻辑设备的模块; /dev/dm-#  /dev/mapper/VG_NAME-LV_NAME /dev/mapper/vol0-root /dev/VG_NAME/…

    Linux干货 2015-09-19