tiyan 发表于 2018-8-27 08:00:37

shell 正则表达三剑客--awk

  awk命令
  awk和sed一样是流式编辑器,它也是针对文档中的行来操作的,一行一行的去执行。awk比sed更加强大,它能做到sed能做到的。awk工具其实是很复杂的,有专门的书籍来介绍它的使用。
  1 awk命令形式
  awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
  [-F|-f|-v]   大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
  ''         引用代码块
  BEGIN       初始化代码块,主要是引用全局变量,设置FS分隔符
  //         匹配代码块,可以是字符串或正则表达式
  {}         命令代码块,包含一条或多条命令
  ;          多条命令使用分号分隔
  END          结尾代码块,主要是进行最终计算或输出结尾摘要信息
  2 特殊变量符
  $0         表示整个当前行
  $1         每行第一个字段
  NF         字段数量变量
  NR         每行的记录号,多文件记录递增
  FNR          与NR类似,不过多文件记录不递增,每个文件都从1开始
  \t         制表符
  \n         换行符
  FS         BEGIN时定义分隔符
  RS         输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
  ~            匹配,与==相比不是精确比较
  !~         不匹配,不精确比较
  ==         等于,必须全部相等,精确比较
  !=         不等于,精确比较
  &&           逻辑与
  ||         逻辑或
  +            匹配时表示1个或1个以上
  /+/    两个或两个以上数字
  /*/    一个或一个以上数字
  FILENAME 文件名
  OFS          输出字段分隔符, 默认也是空格,可以改为制表符等
  ORS          输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
  -F'[:#/]'      定义三个分隔符
  3 实例解析
  
  截取文档中的某个段
  # head -n2 /etc/passwd |awk -F ':' '{print $1}'
  root
  bin
  解释一下,-F 选项的作用是指定分隔符,如果不加-F指定,则以空格或者tab为分隔符。 Print为打印的动作,用来打印出某个字段。$1为第一个字段,$2为第二个字段,依次类推,$0表示整行。
  # head -n2 test.txt |awk -F':' '{print $0}'
  rto:x:0:0:/rto:/bin/bash
  operator:x:11:0:operator:/roto:/sbin/nologin
  注意awk的格式,-F后紧跟单引号,然后里面为分隔符,print的动作要用 { } 括起来,否则会报错。print还可以打印自定义的内容,但是自定义的内容要用双引号括起来。
  # head -n2 test.txt |awk -F':' '{print $1"#"$2"#"$3"#"$4}'
  rto#x#0#0
  operator#x#11#0
  匹配字符或字符串
  # awk '/oo/' test.txt
  operator:x:11:0:operator:/rooto:/sbin/nologin
  roooto:x:0:0:/rooooto:/bin/bash
  # awk -F ':' '$1 ~/oo/' test.txt
  roooto:x:0:0:/rooooto:/bin/bash
  可以让某个段去匹配,这里的’~’就是匹配的意思
  # awk -F ':' '/root/ {print $1,$3} /test/ {print $1,$3}' /etc/passwd
  root 0
  operator 11
  test 511
  test1 512
  awk还可以多次匹配,如上例中匹配完root,再匹配test,它还可以只打印所匹配的段。
  条件操作符
  # awk -F ':' '$3=="0"' /etc/passwd
  root:x:0:0:root:/root:/bin/bash
  awk中是可以用逻辑符号判断的,比如 ‘==’ 就是等于,也可以理解为 ‘精确匹配’ 另外也有 >, ‘>=, ‘20' /etc/passwd
  postfix:x:89:89::/var/spool/postfix:/sbin/nologin
  abrt:x:173:173::/etc/abrt:/sbin/nologin
  sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
  tcpdump:x:72:72::/:/sbin/nologin
  user11:x:510:502:user11,user11's office,12345678,123456789:/home/user11:/sbin/nologin
  test:x:511:511::/home/test:/bin/bash
  test1:x:512:511::/home/test1:/bin/bash
  也可以配合段匹配一起使用:
  # awk -F ':' 'NR>20 && $1 ~ /ssh/' /etc/passwd
  sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
  awk可以把段值更改
  # head -n 3 /etc/passwd |awk -F ':' '$1="root"'
  root x 0 0 root /root /bin/bash
  root x 1 1 bin /bin /sbin/nologin
  root x 2 2 daemon /sbin /sbin/nologin
  awk还可以对各个段的值进行数学运算
  # head -n2 /etc/passwd
  root:x:0:0:root:/root:/bin/bash
  bin:x:1:1:bin:/bin:/sbin/nologin
  # head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4}'
  # head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4; print $0}'
  root x 0 0 root /root 0
  bin x 1 1 bin /bin 2
  当然还可以计算某个段的总和
  # awk -F ':' '{(tot=tot+$3)}; END {print tot}' /etc/passwd
  2891
  这里的END要注意一下,表示所有的行都已经执行
  # awk -F ':' '{if ($1=="root") print $0}' /etc/passwd
  root:x:0:0:root:/root:/bin/bash
  日常应用
  应用1
  awk -F: '{print NF}' helloworld.sh          输出文件每行有多少字段
  awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh输出前5个字段
  awk -F: '{print $1,$2,$3,$4,$5}' OFS='\t' helloworld.sh 输出前5个字段并使用制表符分隔输出
  awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh 制表符分隔前5个字段,并打印行号
  应用2
  awk -F'[:#]' '{print NF}'helloworld.sh   指定多个分隔符: #,输出每行多少字段
  awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh制表符分隔输出多字段
  应用3
  awk -F'[:#/]' '{print NF}' helloworld.sh      指定三个分隔符,并输出每行字段数
  awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6}' helloworld.sh制表符分隔输出多字段
  应用4
  计算/home目录下,普通文件的大小,使用KB作为单位,int是取整的意思

  ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total>
  ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total>  统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少
  netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum}'
  应用6
  统计/home目录下不同用户的普通文件的总数是多少
  ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum}'
  mysql      199
  root         568
  统计/home目录下不同用户的普通文件的大小总size是多少
  ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum/1024/1024,"MB"}'

页: [1]
查看完整版本: shell 正则表达三剑客--awk