正则表达式三剑客之——awk命令

一、什么是awk

awk本身是一种编程语言,主要用于unix/linux里对文本进行处理,也是一个工具。awk处理数据也是逐行扫描文件,从第一行到最后一行,寻找匹配特定模式的行,在这些行上进行你所要的操作,如果没有处理动作,它也会显示到标准输出(屏幕)如果没有指定模式,那么对所有的行进行处理。我们现在所用的awk其实是gawk

[root@server ~]# which awk
/usr/bin/awk
[root@server ~]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 4月  24 06:05 /usr/bin/awk -> gawk

二、工作原理

在这里插入图片描述

三、语法格式

awk 【选项】‘commands’ filename
如果需要引用变量则用双引号,可以和正则一起使用
动作要用花括号{}包住,多个语句用分号;隔开

常用选项:
-F 定义字段分隔符,默认分隔符是空格或制表符
-v 定义变量并赋值
-f 指定文件里的命令来处理文件

commands命令部分:
BEGIN{}:读文件之前的动作,通常用于定义变量
{}:处理文件
END{}:读文件之后的动作

四、内建变量

变量 含义
NR 行号 NR==1,NR<=5
NF 行的字段个数(列数)
FS 分隔符,默认为空格
OFS 定义输出字段分隔符,默认空格
RS 输入记录分隔符,默认换行
ORS 输出记录分隔符,默认换行
$0 当前处理行的所有记录
$1,$2… 文件中每行以间隔符号分隔的不同字符

五、配置实例

1、关于分隔符

打印第一列内容,没有指定字段分隔符,默认是以空格分隔

[root@server ~]# awk '{print $1}' /etc/hosts
127.0.0.1
::1

以冒号分隔,打印第一列内容

[root@server ~]# awk -F: '{print $1}' passwd.txt 
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

以冒号分隔,打印第一列和第二列内容

[root@server ~]# awk -F: '{print $1,$2}' passwd.txt 
root x
bin x
daemon x
adm x
lp x
sync x
shutdown x
halt x
mail x
operator x

2、BEGIN{}……END{}

处理之前做什么动作→处理文件→处理完了做什么动作,不一定成对出现

打印第一列之前,声明分隔符为冒号

[root@server ~]# awk BEGIN'{FS=":"} {print $1}' passwd.txt 
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

以冒号分隔,打印第一列和第二列

[root@server ~]# awk BEGIN'{FS=":"} {print $1,$2}' passwd.txt 
root x
bin x
daemon x
adm x
lp x
sync x
shutdown x
halt x
mail x
operator x

以冒号分隔,字段输出符为–,打印第一列和第二列

[root@server ~]# awk BEGIN'{FS=":";OFS="--"} {print $1,$2}' passwd.txt 
root--x
bin--x
daemon--x
adm--x
lp--x
sync--x
shutdown--x
halt--x
mail--x
operator--x

3、搭配正则表达式

跟sed一样,awk也可以使用正则表达式,也是用在/ /中间
打印root所在的行

[root@server ~]# awk '/root/' passwd.txt 
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

不打印root所在的行

[root@server ~]# awk '!/root/' passwd.txt 
bin:x:1:1:bin:/bin:/sbin/nologin
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:sync:/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/spool/mail:/sbin/nologin

以冒号分隔,打印第三列等于0的行

[root@server ~]# awk -F: '$3==0' passwd.txt 
root:x:0:0:root:/root:/bin/bash

这里如果是字符串的话等号右边需要用双引号将字符串引起来
以冒号分隔,打印第七列等于/bin/bash的行

[root@server ~]# awk -F: '$7=="/bin/bash"' passwd.txt 
root:x:0:0:root:/root:/bin/bash

以冒号分隔,打印第三列小于5的行,{print $0}不写默认也是打印

[root@server ~]# awk -F: '$3<5{print $0}' passwd.txt 
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
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

打印root所在行的第一列

[root@server ~]# awk -F: '/root/{print $1}' passwd.txt 
root
operator

4、使用内建变量

打印每一行和每一行的行号,中间用空格分隔,两个文件NR行号是累加的

[root@server ~]# awk '{print NR,$0}' passwd.txt /etc/hosts
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
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
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 operator:x:11:0:operator:/root:/sbin/nologin
11 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
12 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

打印两个文件的行号,FNR行号是不累加的,是分别打印的

[root@server ~]# awk '{print FNR,$0}' passwd.txt /etc/hosts
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
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
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 operator:x:11:0:operator:/root:/sbin/nologin
1 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

打印第一行到第五行的行号和内容

[root@server ~]# awk 'NR==1,NR==5{print NR,$0}' passwd.txt 
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
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

打印第一行或者打印第五行的内容

[root@server ~]# awk 'NR==1 || NR==5{print $0}' passwd.txt 
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

打印第三行到第五行的内容

[root@server ~]# awk 'NR>=3 && NR<=5{print $0}' passwd.txt 
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

打印每一行的列数和每一行最后一列的内容

[root@server ~]# awk -F: '{print NF,$NF}' passwd.txt
7 /bin/bash
7 /sbin/nologin
7 /sbin/nologin
7 /sbin/nologin
7 /sbin/nologin
7 /bin/sync
7 /sbin/shutdown
7 /sbin/halt
7 /sbin/nologin
7 /sbin/nologin

以冒号分隔,打印倒数第二列

[root@server ~]# awk -F: '{print $(NF-1)}' passwd.txt
/root
/bin
/sbin
/var/adm
/var/spool/lpd
/sbin
/sbin
/sbin
/var/spool/mail
/root

以冒号和制表符为分隔,打印第三列

[root@server ~]# cat 123.txt 
1 2 3 4:5:6	7	8	9

[root@server ~]# awk -F"[:\t]" '{print $3}' 123.txt 
6
[root@server ~]# awk -F"[:\t]" '{print $5}' 123.txt 
8

RS是记录分割,默认是按换行符为一行内容的,而FS是以字段分割,注意区别!
RS意思是遇见谁就把它当做一行的分隔符,然后输出内容
ORS意思是本来每一行的分隔符是换行符,现在不想以换行符当做一行的分割,想以空格当每一行的间隔,那么ORS=“ ”就可以了

以空格分隔每一行内容并打印

[root@server ~]# awk -F: 'BEGIN{RS=" "};{print $0}' 123.txt 
1
2
3
4:5:6	7	8	9

以制表符为分隔每一行内容并打印

[root@server ~]# awk -F: 'BEGIN{RS="\t"};{print $0}' 123.txt 
1 2 3 4:5:6
7
8
9

每一行以制表符为分隔符分隔行

[root@server ~]# awk -F: 'BEGIN{ORS="\t"};{print $0}' 123.txt 
1 2 3 4:5:6	7	8	9	[root@server ~]# 

打印第二列内容并以空格为分隔符

[root@server ~]# awk -F: 'BEGIN{ORS=" "};{print $2}' 123.txt 
5 [root@server ~]# 

因为{print $1,$2}的$1和$2之间的逗号会映射到OFS变量的空格,所以我们输出第一列和第二列之间会以空格显示,那么我们不想输出的时候以空格分,那么你想用什么分就把逗号换成什么就可以了,如果不指定的话就是紧挨着输出

[root@server ~]# awk 'BEGIN{FS=":"};{print "用户名是"$1"****shell是:"$NF}' passwd.txt 
用户名是root****shell是:/bin/bash
用户名是bin****shell是:/sbin/nologin
用户名是daemon****shell是:/sbin/nologin
用户名是adm****shell是:/sbin/nologin
用户名是lp****shell是:/sbin/nologin
用户名是sync****shell是:/bin/sync
用户名是shutdown****shell是:/sbin/shutdown
用户名是halt****shell是:/sbin/halt
用户名是mail****shell是:/sbin/nologin
用户名是operator****shell是:/sbin/nologin

5、其他用法

打印第一列和第三列,中间不分隔

[root@server ~]# awk -F: '{print $1 $3}' passwd.txt 
root0
bin1
daemon2
adm3
lp4
sync5
shutdown6
halt7
mail8
operator11

每一行都打印root

[root@server ~]# awk '{print "root"}' passwd.txt 
root
root
root
root
root
root
root
root
root
root

花括号里print后面要跟变量,如果不是变量其他任何字符都需要用双引号引起来,你想打印什么它就会输出什么

[root@server ~]# date
20200729日 星期三 17:03:14 CST

[root@server ~]# date | awk '{print "year:"$1"\n""month:"$2}'
year:2020年
month:07

打印第一列第二列和第三列并对齐

[root@server ~]# awk -F: '{printf "%-15s %-10s %-15s\n",$1,$2,$3}' passwd.txt 
root            x          0              
bin             x          1              
daemon          x          2              
adm             x          3              
lp              x          4              
sync            x          5              
shutdown        x          6              
halt            x          7              
mail            x          8              
operator        x          11             

printf默认是不换行的,所以要加上\n
%s表示字符类型,%d表示数值类型,%f表示浮点型
%-15s表示字符输出宽度一共15个字符,不足用空格不足到15位。
-表示左对齐,默认不加是右对齐
这样做的方式是可以使格式对齐

猜你喜欢

转载自blog.csdn.net/shengjie87/article/details/107664320