Linux正则表达式——awk命令

Linux正则表达式——awk命令

Administrator 792 2018-04-27

awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。


awk命令用法

分段打印

  • awk命令相比sed,可以实现分段匹配,使用-F制定分隔符,命令格式为awk -F ':' '{print $1}' [file],其中$1表示分割出的第一段,{}内就是所执行的操作,同样的awk也不会对原文件进行修改;

    [root@evobot ~]# awk -F ':' '{print $1}' passwd 
    root
    bin
    daemon
    adm
    lp
    sync
    
  • awk '{print $0}' [file]可以打印出文件所有内容,在指定分隔符时,使用$0效果相同:

    [root@evobot ~]# head -n 3 passwd | awk -F ':' '{print $0}' 
    root:x:0:0:root:/root:/bin/BASH
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    [root@evobot ~]# head -n 3 passwd | awk '{print $0}' 
    root:x:0:0:root:/root:/bin/BASH
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    
  • awk未指定分隔符时,默认以空格或空白字符为分隔符:

    [root@evobot ~]# cat 1.txt 
    zx cc vv
    sai amsomd sad
    [root@evobot ~]# awk '{print $1,$3}' 1.txt 
    zx vv
    sai sad
    
  • 从上面的命令可以看出,打印多个分段,使用,分割指定的段即可;

  • 打印多个分段时,也可以指定输出分段之间的分隔符,只需要将,改为需要指定的符号并用双引号引起来即可:

    [root@evobot ~]# awk '{print $1"#"$3}' 1.txt 
    zx#vv
    sai#sad
    [root@evobot ~]# awk '{print $1"$"$3}' 1.txt 
    zx$vv
    sai$sad
    

匹配用法

  • awk也可以实现匹配功能,命令为awk '/pattern/' [file]:

    [root@evobot ~]# head -n 3 passwd | awk '/login/'
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    
  • 匹配时可以在指定的段内匹配,如指定$1匹配,那么即使后面的分段有能匹配上关键字的字符串,awk也不会匹配,命令用法为awk -F ':' '$1 ~ /pattern/' [file],这里的~表示匹配的意思,匹配时可以使用正则表达式:

    [root@evobot ~]# head -n 3 passwd 
    root:x:0:0:root:/root:/bin/BASH
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    
    [root@evobot ~]# head -n 3 passwd | awk -F ':' '$1 ~ /bin/'
    bin:x:1:1:bin:/bin:/sbin/nologin
    
    [root@evobot ~]# head -n 3 passwd | awk -F ':' '$1 ~ /oo+/'
    root:x:0:0:root:/root:/bin/BASH
    
  • awk可以进行多个条件的匹配:

    [root@evobot ~]# awk -F ':' '/root/ {print $1, $3} /evobot/ {print $3, $4}' passwd 
    root 0
    1002 1002
    [root@evobot ~]# grep -E 'root|evobot' passwd 
    root:x:0:0:root:/root:/bin/BASH
    evobot:x:1002:1002::/home/evobot:/bin/bash
    

数学运算

  • awk匹配还可以进行数学运算如相等==,比较>=<=和不等!=等条件进行匹配:

    [root@evobot ~]# awk -F ':' '$3==0 {print $1}' passwd 
    root
    
    [root@evobot ~]# awk -F ':' '$3>=1000 {print $1}' passwd 
    centos
    lux
    evobot
    
    [root@evobot ~]# awk -F ':' '$7!="/sbin/nologin" {print $0}' passwd 
    root:x:0:0:root:/root:/bin/BASH
    sync:x:5:0:BUS:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    games:x:12:100:games:/usr/games:/sbin/noooologin
    syslog:x:996:994::/home/syslog:/bin/false
    centos:x:1000:1000:Cloud User:/home/centos:/bin/BASH
    lux:x:1001:1001::/home/lux:/bin/bash
    evobot:x:1002:1002::/home/evobot:/bin/bash
    
  • 如果对数字使用双引号"",awk会将其认为是一个字符串,在比较时会以ASCII码进行比较:

    [root@evobot ~]# awk -F ':' '$3>="1000" {print $0}' passwd 
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:BUS:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spoool/mail:/sbin/nologin
    
  • 除了数字或字符串比较之外,awk还可以对两个字段进行比较,如$3<$4这样的比较:

    [root@evobot ~]# awk -F ':' '$3<$4 {print $0}' passwd 
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    mail:x:8:12:mail:/var/spoool/mail:/sbin/nologin
    games:x:12:100:games:/usr/games:/sbin/noooologin
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    
    [root@evobot ~]# awk -F ':' '$3==$4 {print $0}' passwd 
    root:x:0:0:root:/root:/bin/BASH
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    nobody:x:99:99:Nobody:/:/sbin/nologin
    systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    centos:x:1000:1000:Cloud User:/home/centos:/bin/BASH
    lux:x:1001:1001::/home/lux:/bin/bash
    evobot:x:1002:1002::/home/evobot:/bin/bash
    
    [root@evobot ~]# awk -F ':' '$3>$4 {print $0}' passwd 
    sync:x:5:0:BUS:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    operator:x:11:0:operator:/rooooot:/sbin/nologin
    polkitd:x:999:997:User for polkitd:/:/sbin/nologin
    syslog:x:996:994::/home/syslog:/bin/false
    nginx:x:995:993:Nginx web server:/var/lib/nginx:/sbin/nologin
    
  • 比较条件还可以多个一起使用,如$3>"5" && $3<"7"

    [root@evobot ~]# awk -F ':' '$3>"5" && $3<"7"' passwd # 以ASCII码比较
    daemon:x:59:2:daemon:/sbin:/sbin/nologin
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    
    [root@evobot ~]# awk -F ':' '$3>5 && $3<7' passwd	# 以数字大小比较 
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    
    
  • 条件或比较,使用$3>1000 || $7=="/sbin/nologin":

    [root@evobot ~]# awk -F ':' '$3>1000 || $7=="/bin/BASH"' passwd 
    root:x:0:0:root:/root:/bin/BASH
    centos:x:1000:1000:Cloud User:/home/centos:/bin/BASH
    lux:x:1001:1001::/home/lux:/bin/bash
    evobot:x:1002:1002::/home/evobot:/bin/bash
    
    [root@evobot ~]# awk -F ':' '$3>1000 || $7 ~ /BASH/' passwd 
    root:x:0:0:root:/root:/bin/BASH
    centos:x:1000:1000:Cloud User:/home/centos:/bin/BASH
    lux:x:1001:1001::/home/lux:/bin/bash
    evobot:x:1002:1002::/home/evobot:/bin/bash
    

指定输出定界符

  • awk不仅可以指定处理文档时的定界符,也可以指定输出时打印出来的定界符,命令格式为awk -F ':' '{OFS="#"} $3>1000 || $7 ~/BASH/ {print $1,$3,$7} [file]':

    [root@evobot ~]# awk -F ':' '{OFS="#"} $3>1000 || $7 ~ /BASH/ {print $1,$3,$7}' passwd 
    root#0#/bin/BASH
    centos#1000#/bin/BASH
    lux#1001#/bin/bash
    evobot#1002#/bin/bash
    
  • 匹配条件可以和print放在一个{}里,组成一个操作命令:

    [root@evobot ~]# awk -F ':' '{OFS="#"} {if ($3>1000) {print $1,$3,$7}}' passwd 
    lux#1001#/bin/bash
    evobot#1002#/bin/bash
    

内置变量

  • 上面的指定OFS其实也是awk中的内置变量,常用的内置变量还有NR表示行、NF表示段:

    [root@evobot ~]# head -n 3 passwd | awk -F ':' '{print NR":"$0}'	#打印行号
    1:root:x:0:0:root:/root:/bin/BASH
    2:bin:x:1:1:bin:/bin:/sbin/nologin
    3:daemon:x:59:2:daemon:/sbin:/sbin/nologin
    
    [root@evobot ~]# head -n3 passwd | awk -F ':' '{print NF":"$0}'	#打印每行分成几段
    7:root:x:0:0:root:/root:/bin/BASH
    7:bin:x:1:1:bin:/bin:/sbin/nologin
    7:daemon:x:59:2:daemon:/sbin:/sbin/nologin
    
  • NRNF还可以作为判断条件,例如打印前十行,在sed中命令为sed -n '1,10'p [file],使用awk的命令为awk -F ':' 'NR<=10' [file]:

    [root@evobot ~]# awk -F ':' 'NR<=10' passwd 
    root:x:0:0:root:/root:/bin/BASH
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:59:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:BUS:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spoool/mail:/sbin/nologin
    operator:x:11:0:operator:/rooooot:/sbin/nologin
    
    # 打印前十行中第一段为root或者sync的行
    [root@evobot ~]# awk -F ':' 'NR<=10 && $1 ~/root|sync/' passwd 
    root:x:0:0:root:/root:/bin/BASH
    sync:x:5:0:BUS:/sbin:/bin/sync
    
  • NF作为条件可以对段数进行判断,如打印分段数为6的行:

    [root@evobot ~]# awk -F ':' 'NF==6 {print $0}' passwd 
    adm:3:4:adm:/var/adm:/sbin/nologin
    
  • 当使用$NF$NR,这两个变量的意义不同,如awk -F ':' '{print $NR":"$NF}' [file],这条命令会在每读取一行,输出NR对应的$行号:$段数,由于NF是固定的数字,所以$NR超过段数时,输出为空:

    [root@evobot ~]# awk -F ':' '{print $NR":"$NF'} passwd 
    root:/bin/BASH
    x:/sbin/nologin
    59:/sbin/nologin
    adm:/sbin/nologin
    lp:/sbin/nologin
    /sbin:/bin/sync
    /sbin/shutdown:/sbin/shutdown
    :/sbin/halt
    :/sbin/nologin
    :/sbin/nologin
    :/sbin/noooologin
    

赋值

  • 使用=表示给变量赋值,如在awk中使用$1="root",则所有的输出行的$1都变成了root

    [root@evobot ~]# head -n 3 passwd | awk -F ':' '$1="awk"'
    awk x 0 0 root /root /bin/BASH
    awk x 1 1 bin /bin /sbin/nologin
    awk x 59 2 daemon /sbin /sbin/nologin
    
    [root@evobot ~]# head -n3 passwd | awk -F ':' '{OFS=":"} $1="root"'
    root:x:0:0:root:/root:/bin/BASH
    root:x:1:1:bin:/bin:/sbin/nologin
    root:x:59:2:daemon:/sbin:/sbin/nologin
    

END用法

  • 求和整个文件的一列数据并打印结果,需要使用END

    [root@evobot ~]# awk -F ':' '{(sum=sum+$3)}; END {print sum}' passwd 
    8969
    

    这其中{(sum=sum+$3)}是我们自己定义的累加求和的公式,也可以使用{(tot=tot+$3)},tot表示求和;

    END表示计算完成后最后执行的语句。