awk基本用法

1. 简单实例
 awk -F ":" '{print $3}'  test.txt 
 分析: 把test.txt的做如下处理:
           以:为分隔符,该行就被切割成多个”字段“(列)
           各列为 $1  $2 ....
        每一行,执行的操作为:  '{print $3}' 
        这里的操作为: 打印这一行的第3列,打印后自动换行。
 注意:1)如果不用-F指定分隔符,那么分隔符就是一个或多个空格
       2)$1表示这一行的被分隔后的第1列
          $2表示这一行的被分隔后的第2列
          $0表示这一行!
 
# awk  '{print $0}'  /etc/passwd
 效果:把/etc/passwd的每1行打印输出。
 
# awk  -F ":"  '{print "--->" $0}'  test.txt
 
 
test.txt的内容如下:
2016-12-03-zhanshang
2016-11-30-lishi
2015-8-15-wangwu 
 
打印
12月03日
11月30日
8月15日
 
awk -F "-" '{print $2 "月" $3 "日" }'  test.txt
 
 
/etc/passwd的内容格式如下:
---------------------------------------
fab:x:400:1007::/tmp/fab:/sbin/nologin
test1:x:912:912::/tmp/test1:/bin/bash
aaa:x:913:913::/tmp/aaa:/bin/bash
bbb:x:914:914::/tmp/bbb:/bin/bash
ccc:x:300:1008::/tmp/ccc:/sbin/nologin
---------------------------------------
要求打印系统的所有用户的用户名以及家目录,类似如下效果, 要求使用awk实现
补充:对/etc/passwd进行分析
 
username=fab,home=/tmp/fab
username=test1,home=/tmp/test1
username=aaa,home=/tmp/aaa
username=bbb,home=/tmp/bbb
username=ccc,home=/tmp/ccc
 
awk -F ":" '{print "username=" $1 ",home=" $6 }' /etc/passwd
 
 
有销售表如下:
sales.txt
------------------------------
zhangshan  development  20000
lishi      shichang     15000
wangwu     yunwei       18000
------------------------------
把每个员工的工资打印输出:
zhangshan的工资是20000
lishi的工资是15000
wangwu的工资是18000
 
 
打印当前目录下每个文件的大小
类似如下效果:
a.txt:354bytes
m:10234bytes
 
ll | awk 'NR>1{print $9 ":" $5 "bytes" }'
补充: NR表示当前的行号(从1开始)
 
2. awk的BEGIN和END模块
---------- sales.txt ----------------
zhangshan-2000
lishi-1000
wangwu-3000
-------------------------------------
# awk -F "-" 'BEGIN{sum=0} {sum=sum+$2} END{print sum}' sales.txt
# 6000
 
BEGIN模块在分析第1行之前执行,
END模块在分析最后1行之后执行
 
3.awk支持的运算符:
1) 算数运算
   + -  * / %(取余数)
 
   ++  
      a++ 就相当与 a=a+1
   --
      a-- 就相当与 a=a-1
2)赋值运算符
   =  
   +=  例如: a+=b 就相当与 a=a+b
   -=
   *=
   /= 
   %=
 
3) 关系运算符
   >  大于
   >= 大于或等于   
   <  
   <= 
   == 等于
   != 不等于
  
4) 逻辑运算符
   逻辑运算的结果,只有两种:真 假
 
   逻辑与 &&
   a >= 60  && a <= 100
   特点:
   1)只有两个都为真,结果才是真
   2)只有第1个为真,后计算后一个
    
   逻辑或 ||
   a > 100  ||  a < 0
   特点:
   1)只有有1个是真,结果就为真!
   2)如果前1个为真,那么后1个就不计算!
 
 
---------- sales.txt ----------------
zhangshan-2000
lishi-1000
wangwu-3000
-------------------------------------
统计销售额超过1500的有多少人
 
awk -F "-" 'BEGIN{count=0} {$2>1500 && count++} END{print count}' sales.txt
 
打印当前目录下,文件大小超过100个字节的文件名 (了解)
ll | awk '{if ($5 > 5000) {print $9}}'
 
4. 指定多种分隔符
使用awk来获取本机的IP地址
ifconfig eth0 | awk -F [" ":]+ 'NR==2{print $4}'
 
说明:[]表示其中的字符任取1个
      +表示,其前导字符可连续任意多个。
      [" ":]+ 就表示1个或多个的空格,和,1个或多个的:都作为分隔符
2012-12:zhangshan-3000:development
表示development部门的zhangshang在2012-12的工资为3000
要求打印工资(3000)
echo 2012-12:zhangshan-3000:development | awk -F "[:-]" '{print $4}'
 
2012-12:zhangshan------3000:development
echo 2012-12:zhangshan------3000:development | awk -F "[:-]+" '{print $4}'
 
打印eth0的广播地址
ifconfig eth0 | awk -F [" ":]+ 'NR==2{print $6}'
 
5. awk中的print和printf
1)print自动换行
   printf不换行
2)printf能够指定输出格式
   printf("name=%s,age=%d,height=%.2f",
   
   shell中也有printf命令
   # printf "name=%s,age=%d,heig=%.2f \n"  "pzj" 36  79.12345
    
     name=pzj,age=36,heig=79.12
      
   说明: %s, %d都称为占位符
          %s 对应1个字符串
          %d 对应1个整数
          %f 对应1个带小数点的数
          %.2f表示,小数点之后保留2位数字
          \n表示换行符
 
实例:
print
#echo "2016-12-31 pzj 36" | awk '{print "name=" $2 "age=" $3}'
name=pzjage=36
 
#echo "2016-12-31 pzj 36" | awk '{print "name=" $2 ", age=" $3}'
name=pzj, age=36
 
printf
pzj 36" | awk '{printf "name=%s,age=%d\n",$2,$3}'
name=pzj,age=36
 
注意:shell编程中的printf和awk中使用的printf的区别:
      awk中的printf中需要使用逗号,来分隔各个参数
      shell中的printf中需要使用空格,来分隔各个参数
 
6. awk中的正则匹配

打印当前目录中,以day开头的为文件的属主。
ll | awk '$9~/^day/{print $3 "," $9}'
 
$9~/^day/
表示,第9列如果以day开头,那么结果为真
~可以理解为,是一个正则运算符。
注意: 正则表达式,其实,就是一个字符串的匹配规则。
 
使用形式:
    字符串~正则表达式
    $9~/^day/
 
正则表达式,以/开头,以/结尾
^day, 表示以day开头
 
打印当前目录下的所有普通文件的文件名
普通文件(ll的输出形式中,以-开头)
 wk '$1~/^-/{print $9}' 
 
常用的正则表达式
/root/    表示包含root
/^root/   表示需要以root开头
/root$/   表示需要以root结尾
/br..t/    表示,是5个字符的组合
           前2个字符是br, 最后1个是t
           中间的是任意2个字符。
           即  . 用来匹配1个任意字符。
           broot
           browt
/br*t/     *用来匹配任意多个(包含0个)前导字符
           比如:
           /br*t/ 可匹配
           brt   
           brrt
           brrrrrt
 /br+t/    +用来匹配1个或多个前导字符
           /br+t/ 可匹配
           brrt
           brrrrt
 /br?t/    ?用来匹配0个或1个前导字符
           /br?t/ 可匹配
           brt
           brrt
 /a[bcd]m/  []用来匹配方框号内的任意一个字符
           /a[bcd]m/ 可匹配
           abm
           acm
           adm
 a[^bcd]m  []内的^,表示除了其后的任意1个字符。
           a[^bcd]m 
           可匹配:    a1m
                      axm
                      ...
           不可匹配: abm
                      acm
                      adm
字符串 ~ 正则表达式
          如果前面的字符串 匹配 后面的正则表达式,那么结果就为真
字符串 !~ 正则表达式
          如果前面的字符串 不匹配 后面的正则表达式,那么结果就为真
       
/etc/passwd
1) 统计当前系统,有哪些用户可以登录系统
awk -F ":" '$9!~/nologin$/{print $1}' /etc/passwd
awk -F ":" '$0!~/nologin$/{print $1}' /etc/passwd
 
2) 统计当前系统中,有多少个系统用户( 0 < uid < 500)
方式1
 awk -F ":" 'BEGIN{count=0} {$3 > 0 && $3 < 500 && count++} END{print count}'
/etc/passwd
 
方式2
awk -F ":" 'BEGIN{count=0} {if ($3 > 0 && $3 < 500) {count++}}  END{print
count}' /etc/passwd
 
3)  统计当前系统中,哪些用户的家目录在/home/下。
awk -F ":" '$6~/^\/home/{print $1 "  " $6}' /etc/passwd
 
awk的常用函数
1. gsub
# awk 'BEGIN{info="this is a test2016test!"; \
           gsub(/[0-9]+/,"XXX", info); \
           print info}'
输出:
this is a testXXXtest!
 
gsub的作用:字符串的替换!
 
[0-9]  就相当与 [0123456789],即0到9中的任意1个数字!
[0-9]+ 就表示任意1个数字字符串,但是长度至少是1
 
小结: gsub(正则表达式, 替换字符串,源字符串)
 
1)把 字符串 "China-sz-20160812" 修改为 "China-sz-16"
awk 'BEGIN{info="China-sz-20160812";gsub(/[0-9]+/, 16, info);print info}'
 
2) 有文件如下
   ------------------------
   zhangshan   sz   3000
   lishi       sz   5000
   ------------------------
   修改为
   ------------------------
   zhangshan  深圳  3000
   lishi      深圳  5000
   ------------------------
   方法1:
   awk '{$2=="sz" && $2="深圳"; print $0}'  test.txt
 
   方法2:
   awk '{gsub(/sz/, "深圳", $0); print $0}' test.txt
3) /etc/hosts的内容如下:
   ------------------------
   192.168.1.5  zhangshan.com
   192.168.2.8  lishi.com
   ------------------------
   修改为
   ------------------------
   10.0.1.5   zhangshan.com
   10.0.2.8   lishi.com
   ------------------------
 
   awk '{gsub(/192.168/, "10.0", $0); print $0}' test.txt
    
 2. index 
    awk 'BEGIN{info="this is a dog2016dog!"; print index(info, "dog")}'
    注释:index(info, "dog")
          在info中查找"dog", 返回"dog"第一次出现的位置
          如果找不到,就返回0
          如果返回值大于0,就表示包含指定的字符串。
   
    补充:三目运算符 ?:
          awk中支持 三目运算符
          双目运算符: a+b
          单目运算符: a++
          三目运算符: print  salary>20000 ? "买包" :  "看包"
          awk 'BEGIN{salary=25000; print (salary>20000) ? "买包" : "看包"}
 
    
    有文件如下
    -------------------
    zhangshan   深圳龙华区,长沙,上海   
    lishi       广州,北京
    wangwu      武汉,深圳南山区
    -------------------
    把需要到深圳出差的员工姓名打印输出。
    要求使用多种方法实现,要求使用index
 
    方法1:
    awk '$2~/深圳/{print $1}' test.txt 
     
    方法2:
    awk '{if (index($2, "深圳") > 0) {print $1}}' test.txt
    注意awk中if语句的用法:
     if (条件) { 执行语句 }
 
3. match 
   匹配查找
    有文件如下
    -------------------
    zhangshan   深圳龙华区,长沙,上海   13543827223   32010719801250
    lishi       广州,北京              13223442888   43019519931233
    wangwu      武汉,深圳南山区        13025879997   43019719911233
    -------------------
    要求打印使用联通手机号码的员工
    假设,联通号码是132和130开头的
     
    awk  '{if (match($3, /^13[20]/) > 0) {print $1}}' test.txt 
     
    
    打印所有90后的员工姓名 
    awk  '{if (match($4, /[0-9][0-9][0-9][0-9][0-9][0-9]199[0-9]+/) > 0) {print $1}}' test.txt 
    正则表达式为:/[0-9][0-9][0-9][0-9][0-9][0-9]199[0-9]+/
 
4. 字符串截取substr
    awk 'BEGIN{info="320109199105083480"; age=substr(info,7,4); print age}'
    输出:1991
 
    用法: substr(字符串,起始位置,长度)
    
    打印年龄大于25岁的员工姓名
    文件内容如下:
    -------------------------------------------------------------
   zhangshan   深圳龙华区,长沙,上海   13543827223   32010719801250
   lishi       广州,北京              13223442888   43019519931233
   wangwu      武汉,深圳南山区        13025879997   43019719911233
   ---------------------------------------------------------------
   awk '{ year=substr($4,7,4); \
          age=2016-year; \
          if(age > 25){print $1} \
        }'\
   test.txt
      
  if (条件){ 语句 }
  如果 条件为真, 那么就执行后面大括号内的语句

  

posted @ 2019-12-18 21:41  MlxgzZ  阅读(861)  评论(0编辑  收藏  举报