文本处理awk

awk

记录和字段

每个输入行作为一条记录,由空格或制表符分隔的单词作为字段(用来分隔字段的字符被称为分隔符),默认分隔符是空格。
连续的两个或多个空格和/制表符被称作一个分隔符

  • 以下举例演示以下
[root@localhost ~]# df -h 
Filesystem           Size  Used Avail Use% Mounted on
devtmpfs             451M     0  451M   0% /dev
tmpfs                471M     0  471M   0% /dev/shm
tmpfs                471M  6.6M  464M   2% /run
tmpfs                471M     0  471M   0% /sys/fs/cgroup
/dev/mapper/cs-root  8.0G  5.0G  3.1G  62% /
/dev/sda1           1014M  176M  839M  18% /boot
tmpfs                 95M     0   95M   0% /run/user/0

[root@localhost ~]# df -h | awk '{print $2}'
Size
451M
471M
471M
471M
8.0G
1014M
95M
//第二列之间有很多空格,默认分隔符是空格

字段和引用的分离

awk允许使用字段操作符**$来指定字段,在该操作符后面跟着一个数字或者变量,用于标识字段的位置。
$1表示第一个字段,
$2表示第二个字段,以此类推,但是$0**表示整个输入记录。

  • 以下举例演示一下使用:
//更换输入行的短语顺序
[root@localhost ~]# cat test 
tom wuhan 111-222-333
[root@localhost ~]# awk '{print $2,$3,$1}' test 
wuhan 111-222-333 tom

//$0
[root@localhost ~]# awk '{print $0}' test 
tom wuhan 111-222-333

可以用任何计算值为整数的表达式来表示一个字段,而不只是用数字和变量。

  • 以下举例演示使用整数的表达式:
[root@localhost ~]# echo 'a b c d'|awk 'BEGIN{one=1 ;two=2}{print $(one+two)}'
c

可以在命令行使用-F选项改变字段的分隔符,他后面跟着(或者紧跟着,或者有空白)分隔符

  • 以下举例演示使用-F:
[root@localhost ~]# cat test 
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@localhost ~]# awk -F':' '{print $1,$2}' test 
root x
bin x
daemon x
//-F后面指定的分隔符最好是使用引号,这样便于分辨

//可以指定任意自己需要的为分隔符,也可以含有正则表达式
[root@localhost ~]# awk -F'[0-9]+' '{print $1}' test 
root:x:
bin:x:
daemon:x:

  • 经典示例,取出主机IP地址
[root@localhost ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:03:ca:ed brd ff:ff:ff:ff:ff:ff
    inet 192.168.218.133/24 brd 192.168.218.255 scope global dynamic noprefixroute ens160
       valid_lft 1622sec preferred_lft 1622sec
    inet6 fe80::6faa:c998:4390:2ee4/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

[root@localhost ~]#  ip a|grep  'inet '|grep -v '127.0.0.1'
    inet 192.168.218.133/24 brd 192.168.218.255 scope global dynamic noprefixroute ens160

//使用awk取出IP
[root@localhost ~]#  ip a|grep  'inet '|grep -v '127.0.0.1'
    inet 192.168.218.133/24 brd 192.168.218.255 scope global dynamic noprefixroute ens160
[root@localhost ~]#  ip a|grep  'inet '|grep -v '127.0.0.1'|awk '{print $2}'|awk -F'/' '{print $1}'
192.168.218.133
//以上取出了主机IP,但是使用了两次awk,过程比较繁琐,以下我们使用一次awk取出,简单明了

[root@localhost ~]#  ip a|grep  'inet '|grep -v '127.0.0.1'|awk -F'[ /]+' '{print $3}'
192.168.218.133
//把空格和/同时作为分隔符,以此来取出IP

在脚本中指定域分隔符是一个好习惯,可以定义系统变量FS来改变字段分隔符,必须在由BEGIN中来指定这个变量。

BEGIN {FS=","}

FS为输入分隔符,OFS为输出分隔符
我们在指定分隔符时使用**-F**,也可以使用FS来指定

[root@localhost ~]# cat test 
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@localhost ~]# awk 'BEGIN{FS=":";OFS="-"}{print $2,$3}' test 
x-0
x-1
x-2

注意:在使用awk时,外层使用单引号’’,内层使用双引号“ ”

可以编写匹配规则来修改操作符打印除特定的内容,可以使用正则表达式

//打印号码较为常见,以下举例演示
[root@localhost ~]# cat test 
707-724-0000
(707) 724-0000
(707)724-0000
1-707-724-0000
1 707-724-0000
1(707)724-0000

//如果想要输出以上test的内容,我们尝试编写以下匹配规则
[root@localhost ~]# awk '/1?[ -]?\(?[0-9]+\)?[ -]?[0-9]+-[0-9]+/' test 

//尝试取出test中的
(707) 724-0000
(707)724-0000
[root@localhost ~]# awk '/^\([0-9]+\) ?[0-9]+-[0-9]+/' test 
(707) 724-0000
(707)724-0000

表达式

  • 常用转译序列
序列描述
\n换行符
\t水平制表符(Tab)
\r回车
  • 算术操作符
操作符描述
+
-
*
/
%取模
^取幂
**平方
  • 赋值操作符
操作符定义
++变量加1
变量减1
+=将加的结果赋给变量
-=将减的结果赋给变量
*=将乘的结果赋给变量
/=将除的结果赋给变量
%=将取模的结果赋给变量
^=将取幂的结果赋给变量
**=将取幂的结果赋给变量.a

在awk中,变量没有赋予值时,默认是0

[root@localhost ~]# awk 'BEGIN{y=x+1;print y}'
1

以下举例演示用于计算一个文件中空行的目录:

//统计空行数量,test中有两行空行
[root@localhost ~]# cat test 
707-724-0000
(707) 724-0000
(707)724-0000
1-707-724-0000
1 707-724-0000
1(707)724-0000


[root@localhost ~]# awk '/^$/{print x+=1}' test 
1
2

既然可以匹配空行,那么就可以匹配需要的任意内容匹配,自己根据自己的需要来匹配

++x 在返回结果前递增x的值(前缀)
x++ 在返回结果后递增x的值(后缀)

[root@localhost ~]# awk '/^$/{print ++x}' test 
1
2

[root@localhost ~]# awk '/^$/{print x++}' test 
0
1

以上我们都是遇到空行时就会打印空行的数值,我们现在可以计算所有的空行的值后再打印空行的总数,在END模式中放置print语句,当读完最后一个空行后打印x的值:

[root@localhost ~]# awk '/^$/{++x}END{print x}' test 
2

计算学生的平均值

[root@localhost ~]# cat test 
tom 88 99 77 66 55 
jerry 66 76 87 98 72
lisi 55 78 98 96 82

[root@localhost ~]# awk '{sum=$2+$3+$4+$5+$6;avg=sum/5;print $1,avg}' test 
tom 77
jerry 79.8
lisi 81.8

系统变量

前面我们已经介绍了FS输入分隔符,OFS输出分隔符,他们的默认值是一个空格
NR表示行号

[root@localhost ~]# cat test 
可乐
雪碧
冰红茶
矿泉水
奶茶
咖啡
//使用NR显示行号
[root@localhost ~]# awk '{print NR".",$1}' test 
1. 可乐
2. 雪碧
3. 冰红茶
4. 矿泉水
5. 奶茶
6. 咖啡

  • 编写一个脚本实现自动贩卖机的功能
[root@localhost ~]# cat test 
可乐 3
雪碧 3
冰红茶 3
矿泉水 2
奶茶  4
咖啡  5

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

echo "商品列表:"
awk '{print NR".",$1,$2"元"}' test

read -p "请输入您要买的商品编号:" choice
read -p "请输入您要买的数量:" num

awk -vcount=$num -vline=$choice 'NR==line{print "您一共买了"count"瓶,共消费"$2*count"元。"}' test
 
[root@localhost ~]# ./test.sh 
商品列表:
1. 可乐 3元
2. 雪碧 3元
3. 冰红茶 3元
4. 矿泉水 2元
5. 奶茶 4元
6. 咖啡 5元
请输入您要买的商品编号:2
请输入您要买的数量:2
您一共买了2瓶,共消费6元。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值