awk

awk是一种优良的文本处理工具,
linux和unix环境中现有的功能最强大的数据处理引擎之一
awk是三个人的姓的缩写

在linux下的awk实际上是gawk(gun awk)

[root@localhost ~]# which awk
/usr/bin/awk
[root@localhost ~]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 Oct 24 01:54 /usr/bin/awk -> gawk

语法格式

任何awk语句都是由模式动作组成,一个awk脚本可以有多个语句
模式决定动作语句的触发条件和触发时间

  • 模式
    • 正则表达式 /root/ 匹配含有root的行
    • 关系表达式 < > && || + *
    • 匹配表达式 ~ !~
  • 动作
    • 变量 命令 内置函数 流控制语句

语法结构

awk [options]
'BEGIN{ print 'start' }
pattern{ commands }
END{ print 'end' }' file

awk工作的三个步骤

awk支持两种不同类型的变量,内建变量和自定义变量

$n当前记录的第n个字段,比如:$1表示第一个字段,$2表示第二个字段
$0这个变量包含执行过程中当前行的文本内容
FILENAME当前输入文件的名
FS字段分隔符(默认是空格)
NF表示字段数,在执行过程中对应于当前的字段数,NF:列的个数
FNR各文件分别计数的行号
NR表示记录数,在执行过程中对应于当前的行号
OFS输出字段分隔符,(默认值是一个空格)
ORS输出记录分隔符(默认值是一个换行符)
RS记录分隔符(默认值是一个换行符)

常用的命令选项

  • -F fs指定分隔符
  • -v 赋值一个用户自定义变量
  • -f 指定脚本文件,从脚本中读取awk命令

分隔符的使用

[root@localhost ~]# echo AA BB CC DD | awk '{print $2}'
BB
[root@localhost ~]# echo AA,BB,CC,DD | awk -F "," '{print $2}'
BB
[root@localhost ~]# echo "AA|BB|CC|DD" | awk -F "|" '{print $2}'
BB
[root@localhost ~]# echo "aergdfsshbtryhgdfshrts" | awk -Fbt '{print $1}'
aergdfssh
[root@localhost ~]# echo "aergdfsshbtryhgdfshrts" | awk 'BEGIN{FS="bt"} {print $1}'
aergdfssh

过滤出当前系统的IP地址

[root@VM_0_7_centos ~]# ifconfig eth0 | grep netmask
        inet 172.17.0.7  netmask 255.255.240.0  broadcast 172.17.15.255

[root@VM_0_7_centos ~]# ifconfig eth0 | grep netmask | awk '{print $2}'
172.17.0.7

指定多个分隔符

[root@localhost ~]# echo "aergdfsshbtryhgdfshrts" | awk -F[fb] '{print $1}'
aergd
[root@localhost ~]# echo "aergdfsshbtryhgdfshrts" | awk -F[fb] '{print $2}'
ssh

关系运算符的使用

[root@VM_0_7_centos ~]# cat a.txt
4 5 6 7 8
5 6 7 8 9
6 7 8 9 10
[root@VM_0_7_centos ~]# awk '{print $1+10}' a.txt
14
15
16

取最后一个值

[root@VM_0_7_centos ~]# echo "one two three four" | awk '{print $4}'
four

[root@VM_0_7_centos ~]# echo "one two three four" | awk '{print $NF}'
four

取倒数第二个值

[root@VM_0_7_centos ~]# echo "one two three four" | awk '{print $(NF-1)}'
three

取第二个值

[root@VM_0_7_centos ~]# echo "one two three four" | awk '{print $(NF/2)}'
two

统计当前内存的使用率

[root@localhost ~]# cat frees.sh
#! /bin/bash

i=`free -m | grep Mem | awk '{print (($3/$2)*100)"%"}'`
echo -e "内存使用百分百:  \e[31m$i \e[0m"
[root@localhost ~]# bash frees.sh
内存使用百分百:  16.2551%

输出多个值

打印出passwd文件中用户UID小于10的用户名和它登录所使用的shell

在两个字段中添加符号

[root@VM_0_7_centos ~]# awk -F ':' '$3<10{print $1 "<==>" $NF}' /etc/passwd
root<==>/bin/bash
bin<==>/sbin/nologin
daemon<==>/sbin/nologin
...

在两个字段中添加制表符

[root@VM_0_7_centos ~]# awk -F ':' '$3<10{print $1 "\t" $NF}' /etc/passwd
root    /bin/bash
bin /sbin/nologin
daemon  /sbin/nologin
...

输出多个列时,可以加','分隔

[root@VM_0_7_centos ~]# awk -F ':' '$3<10{print $1,$NF}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin

打印出系统中UID小于10且登录shell是/bin/bash的用户

[root@VM_0_7_centos ~]# awk -F ':' '$3<10 && $NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash

NR和FNR

输出行号大于等于3且小于6 的行

[root@localhost ~]# awk -F: '(NR>=3 && NR<6){print NR,$0}' /etc/passwd
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

通过NR行号获取IP地址

[root@localhost ~]# ip addr | awk 'NR==9{print $2}'
192.168.0.234/24

NR和FNR的区别

[root@VM_0_7_centos ~]# awk '{print NR"\t" $1}' /etc/hostname /etc/hostname
1   VM_0_7_centos
2   VM_0_7_centos
[root@VM_0_7_centos ~]# awk '{print FNR"\t" $1}' /etc/hostname /etc/hostname
1   VM_0_7_centos
1   VM_0_7_centos

去除输出中的首行提示信息(grep,sed,awk)

[root@VM_0_7_centos ~]# route -n | grep -v ^Kernel
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 eth0
172.17.0.0      0.0.0.0         255.255.240.0   U     0      0        0 eth0
[root@VM_0_7_centos ~]# route -n | sed 1d
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 eth0
172.17.0.0      0.0.0.0         255.255.240.0   U     0      0        0 eth0
[root@VM_0_7_centos ~]# route -n | awk '(NR!=1){print $0}'
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 eth0
172.17.0.0      0.0.0.0         255.255.240.0   U     0      0        0 eth0

正则表达式

使用awk查找出包含root字符的行,三种方法

[root@VM_0_7_centos ~]# awk -F: '/root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@VM_0_7_centos ~]# awk -F: '/root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@VM_0_7_centos ~]# awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

打印以root开头的行

[root@localhost ~]# awk -F: '/^root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

取出以bash结尾的行

[root@VM_0_7_centos ~]# awk -F: '/bash$/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
xue1:x:1000:1000::/home/xue1:/bin/bash
xue2:x:1001:1001::/home/xue2:/bin/bash

取出行中没有root的行

[root@VM_0_7_centos ~]# awk -F: '!/root/{print $0}' /etc/passwd

条件表达式

表达式?if-true:if-false
问号前面是条件,如果条件为真执行if-true
为假执行if-false

如果passwd中UID小于等于10,则给变量USER赋值为aaa,否则赋值为bbb

[root@VM_0_7_centos ~]# awk -F: '{$3<10? USER="aaa":USER="bbb";print $1,USER}' /etc/passwd
root aaa
bin aaa
...
nginx bbb
xue1 bbb
xue2 bbb

如果UID小于10,则输出user=>用户名,否则输出pass=>用户名

[root@VM_0_7_centos ~]# awk -F: '{if($3<10){print "user=>"$1} else{print "pass=>"$1}}' /etc/passwd
user=>root
user=>bin
...
pass=>nginx
pass=>xue1
pass=>xue2
  • ~ 匹配
  • !~ 不匹配

查出UID小于等于5且包括bin/bash的行

[root@VM_0_7_centos ~]# awk -F: '{if($3<=5 && $NF ~ "/bin/bash"){print $1,$NF}}' /etc/passwd
root /bin/bash

引用变量

用-v指定 var=value 变量名区分大小写
在程序中直接定义
在awk中,使用变量不用加$符号

[root@VM_0_7_centos ~]# var='test'
[root@VM_0_7_centos ~]# awk 'BEGIN{print "'$var'"}'
test

printf格式化输出

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

format使用注意事项

format样式

  • %c 显示字符的ACSII码
  • %d,%i 十进制整数
  • %f 显示浮点数
  • %s 显示字符串
  • %% 显示%自身

输出passwd文件中的第一列内容,输出时不会换行

[root@VM_0_7_centos ~]# awk -F: '{printf "%s--",$1}' /etc/passwd
root--bin--daemon--adm--lp--sync--shutdown
...

换行输出

[root@VM_0_7_centos ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd
root
bin
daemon

输出用户名,并在用户名前加字符串'USERNAME'

[root@VM_0_7_centos ~]# awk -F: '{printf "USERNAME: %s\n",$1}' /etc/passwd
USERNAME: root
USERNAME: bin
USERNAME: daemon

对$1和$NF都做格式化输出

[root@VM_0_7_centos ~]# awk -F: '{printf "%s--%s\n",$1,$NF}' /etc/passwd
root--/bin/bash
bin--/sbin/nologin
daemon--/sbin/nologin

awk修饰符

  • N 显示宽度
    • 左对齐

显示时用10个字符串右对齐显示

[root@VM_0_7_centos ~]# awk -F: '{printf "%s--%s\n",$1,$NF}' /etc/passwd
root--/bin/bash
bin--/sbin/nologin
daemon--/sbin/nologin

使用10个宽度,左对齐显示

[root@VM_0_7_centos ~]# awk -F: '{printf "%-10s\n",$1}' /etc/passwd
root
bin
daemon    

第一列使用15个字符宽度左对齐输出,最后一列使用15个字符宽度右对齐输出

[root@VM_0_7_centos ~]# awk -F: '{printf "%-15s%15s\n",$1,$NF}' /etc/passwd
root                 /bin/bash
bin              /sbin/nologin
daemon           /sbin/nologin
[root@VM_0_7_centos ~]# cat test.awk
BEGIN{
  print "UserID\t\t\t\tShell"
  print "---------------------------------------"
  FS=":"
}
$3<10 && $NF=="/bin/bash"{
  printf "%-20s%20s\n",$1,$NF
}
END{
  print "---------------------------------------"
}
[root@VM_0_7_centos ~]# awk -f test.awk /etc/passwd
UserID              Shell
---------------------------------------
root                           /bin/bash
---------------------------------------
12-17 07:33