文本三剑客之AWK详细讲解

1、介绍

awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
相对于sed常常作用于一整个行的处理,awk则比较倾向于一行当中分成数个【字段】处理,因此,awk相当适合处理小型的数据数据处理。同时,awk也是一种报表生成器,就是对文件进行格式化处理的,这里的格式化不是文件系统的格式化,而是对文件内容进行各种“排版”,进而格式化显示;awk有多个版本,目前Centos7上使用的awk属于GNU awk( gawk)

[root@client_1]# ll `which awk`
lrwxrwxrwx. 1 root root 4 Feb  3 05:14 /usr/bin/awk -> gawk

2、基本用法

awk [-v var=value | -F “分隔符”] ‘program’ file

awk [-v var=value | -F “分隔符”] ‘BEGIN{action;… }pattern{action;… }END{action;… }’ file

awk [-v var=value | -F “分隔符” ] -f scripfile file

参数

-F “分隔符”   指定输入分隔符,可以是字符串或正则表达式,如-F:
-v var=value  变量赋值
-f  scripfile  从脚本文件中读取awk命令进行执行

说明

program : 通常放在单引号下面,也就是: pattern{action statements},为awk对数据主要的处理指令

pattern: 为过滤条件,就是对读入的行进行指定的过滤,如果不加,就是所有的行都符合条件

action statements:对过滤后的数据进行的处理,放在{}内指明,输出主要用 print, printf

BEGIN、END都是可选的,BEGIN会在program 执行前就执行,END则是在program执行后执行

分割符、域和记录

• awk执行时,由分隔符分隔的字段(域)标记$1,$2...$n称为域标识。$0
为所有域,注意:此时和shell中变量$符含义不同
• 文件的每一行称为记录
• 省略action,即program只有pattern。则默认会执行 print $0 的操作

Note:
如果 program中字符串不加上"",就会当成变量,数字则不需要,也就是-v var=value 定义了参数,在program中可直接使用

3、awk工作原理

第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
补充:

  1. BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
  2. END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
  3. pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供
    pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块

4、awk用法讲解

4.1、print

print格式:print item1, item2, …
要点:
(1) 逗号分隔符
(2) 输出item可以字符串,也可是数值;当前记录的字段、变量或awk的表达式
(3) 如省略item,相当于print $0

举例:获取当前系统用户及其uid

#$1,$3之间的 “,”,输出后就是 空格
[root@client_1 ~]# awk -F ":" '{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
....

“\t”:以tab键作为分隔符

[root@client_1 ~]# awk -F ":" '{print $1"\t"$3}' /etc/passwd
root	0
bin	1
daemon	2
adm	3
lp	4
sync	5
shutdown	6
halt	7
...

也可以自定义分隔符

[root@client_1 ~]# awk -F ":" '{print $1"---"$3}' /etc/passwd
root---0
bin---1
daemon---2
adm---3
lp---4
...

4.2 、内置和自定义变量

FS:输入字段分隔符,默认为空白字符
OFS:输出字段分隔符,默认为空白字符
RS:输入记录分隔符,指定输入时的换行符
ORS:输出记录分隔符,输出时用指定符号代替换行符
NF:字段数量
NR:记录号
FNR:各文件分别计数,记录号
FILENAME:当前文件名
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行所给定的各参数

举例说明
awk -F “:” 等价于 awk -v FS=":" FS为awk内置的字段分隔符,默认为空白字符

[root@client_1 ~]# awk -v FS=":" '{print $1FS$3}'  /etc/passwd
root:0
bin:1
daemon:2
adm:3
lp:4
...

FS还可以引用shell中的变量

[root@client_1 ~]# fs=":"
[root@client_1 ~]# awk -v FS=$fs '{print $1FS$3}'  /etc/passwd
root:0
bin:1
daemon:2
adm:3
...

查看分区使用情况,并且舍弃掉%

[root@client_1 ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 470M     0  470M   0% /dev
tmpfs                    487M     0  487M   0% /dev/shm
tmpfs                    487M  8.3M  478M   2% /run
tmpfs                    487M     0  487M   0% /sys/fs/cgroup
/dev/mapper/centos-root   17G  4.0G   14G  24% /
/dev/sda1               1014M  171M  844M  17% /boot
tmpfs                     98M   12K   98M   1% /run/user/42
tmpfs                     98M     0   98M   0% /run/user/0
[root@client_1 ~]# df -h | awk -F " +|%" '{print $1,$5}' 
Filesystem Use
devtmpfs 0
tmpfs 0
tmpfs 2
tmpfs 0
/dev/mapper/centos-root 24
/dev/sda1 17
tmpfs 1
tmpfs 0

Note:这种可作为报警,超过80,触发报警机制

以 [ 或空格作为分隔符

awk -F "[\[ ]" '{print $5}' access_log

OFS为输出分隔符,FS是以什么作为分割的,而OFS是分割后,输出的时候,分隔符用什么来表示

[root@client_1 ~]# awk -F ":" -v OFS="--" '{print $1,$3}' /etc/passwd
root--0
bin--1
daemon--2
adm--3
...

RS:输入记录分割符,也就是这个符号定义了到哪是一条记录,默认是换行符 \n.

之前说awk每次读入一行,准确的说,是读入一条记录

下面例子中定义了以“;”结束,才为一条记录

[root@client_1 ~]# cat tets.txt 
aa,bb,cc
dd;eeff;gg,
hh;
[root@client_1 ~]# awk -F "," -v RS=";" '{print $1}' tets.txt 
aa
eeff
gg



ORS是输出行按照什么符号作为记录的分隔符,默认是换行符 \n.

[root@client_1 ~]# cat tets.txt 
aa,bb,cc
dd;eeff;gg,
hh;
[root@client_1 ~]# awk -F "," -v RS=";" '{print $1}' tets.txt 
aa
eeff
gg


[root@client_1 ~]# awk -F "," -v RS=";" -v ORS="#" '{print $1}' tets.txt 
aa#eeff#gg#

NF是字段数量

查看下每行以“:”分割后,有多少个字段

[root@client_1 ~]# awk -F ":" '{print NF}' /etc/passwd
7
7
7
...

$NF则可以代表最后一行

#获取倒数第二行信息

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

获取目前连接的IP地址

[root@client_1 ~]# ss -nt
State       Recv-Q Send-Q                                                           Local Address:Port                                                                          Peer Address:Port              
ESTAB       0      52                                                               192.168.0.101:22                                                                           192.168.0.106:60850
[root@client_1 ~]# ss -nt| awk -F " +|:" '{print $(NF-2)}'
Address
192.168.0.106

NR 记录号,默认情况下是行号

[root@client_1 ~]# awk -F ":" '{print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
4 adm
...

FNR:每个文件独立编号

FILENAME :当前文件名

[root@client_1 ~]# awk -F":" '{print FNR,FILENAME,$1}' /etc/passwd /etc/shadow
1 /etc/passwd root
2 /etc/passwd bin
...
1 /etc/shadow root
2 /etc/shadow bin
3 /etc/shadow daemon 

除了以上这些内置变量,还有其他的变量

自定义变量

[root@client_1 ~]# awk -v NAME='test' 'BEGIN{print NAME}'
test
[root@client_1 ~]# awk -v NAME='test' 'BEGIN{print NAME;NAME="test1";print NAME}'
test
test1

4.3 格式化输出-printf

1、格式化输出:printf “FORMAT”, item1, item2, …
(1) 必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT中需要分别为后面每个item指定格式符
2、 格式符:与item一一对应
%c:显示字符的ASCII码
%d, %i:显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数,默认右对齐
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串,默认右对齐
%u:无符号整数
%%:显示%自身
3、修饰符
#[.#] 第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f

  • 左对齐(默认右对齐) %-15s
  • 显示数值的正负符号 %+d

举例

-%10s:左对齐,占据10个宽度,为字符串
%4.1f代表浮点数,占据4个宽度,其中1个小数位,取第一个小数(不是四舍五入)
%s、%f默认都是右对齐
[root@client_1 ~]# echo "aaa:123.456" | awk -F ":" '{printf "%-10s %4.1f",$1,$2}' 
aaa        123.5

note:当宽度小于实际值位数的时候,对齐的效果就不会有用

[root@client_1 ~]# awk -F ":" '{printf "%20s--%6d \n",$1,$3}' /etc/passwd
                root--     0 
                 bin--     1 
              daemon--     2 
                 adm--     3 
                  lp--     4 
                sync--     5 
            shutdown--     6 
                halt--     7 
                mail--     8 
                ....
[root@client_1 ~]# awk -F ":" '{printf "%-20s--%6d \n",$1,$3}' /etc/passwd
root                --     0 
bin                 --     1 
daemon              --     2 
adm                 --     3 
lp                  --     4 
sync                --     5 
shutdown            --     6 
halt                --     7 
...
补充:
awk -F: ‘{printf "%s",$1}’ /etc/passwd
awk -F: ‘{printf "%s\n",$1}’ /etc/passwd
awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
awk -F:‘ {printf "Username: %s\n",$1}’ /etc/passwd
awk -F: ‘{printf “Username: %s,UID:%d\n",$1,$3}’  /etc/passwd
awk -F: ‘{printf "Username: %15s,UID:%d\n",$1,$3}’  /etc/passwd
awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd

4.4、操作符

算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x:转换为负数
+x:将字符串转换为数值
字符串操作符:没有符号的操作符,字符串连接
*赋值操作符:
=, +=, -=, =, /=, %=, ^=,++, –

[root@client_1 ~]# awk 'BEGIN{i=1;i++;print i}'
2

比较操作符:
==, !=, >, >=, <, <=

'$3>=1000' 相当于'$3>=1000{print $0}'  默认省略了{print $0}
[root@client_1 ~]# awk -F ":" '$3>=1000' /etc/passwd
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
xulx:x:1000:1000:xulx:/home/xulx:/bin/bash

模式匹配符:
~:左边是否和右边匹配,包含
!~:是否不匹配

查找第一列包含root的行

[root@client_1 ~]# awk -F ":" '$1 ~ "root"' /etc/passwd
root:x:0:0:root:/root:/bin/bash

将/etc/fstab中uuid开头的行显示出来

[root@client_1 ~]# awk '$0 ~ "^UUID"' /etc/fstab 
UUID=9f1ee330-7b0f-4c5f-98e2-64662d483664 /boot                   xfs     defaults        0 0
或
[root@client_1 ~]# awk '$1 ~ "^UUID"' /etc/fstab 
UUID=9f1ee330-7b0f-4c5f-98e2-64662d483664 /boot                   xfs     defaults        0 0

逻辑操作符:与&&,或||,非!
查找UID小于1000的用户

[root@client_1 ~]# awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
root
bin
daemon
adm
lp

查找UID小于100的用户

[root@client_1 ~]# awk -F: '$3<100 {print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
...
或
[root@client_1 ~]# awk -F: '!($3>=100) {print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
...

条件表达式(三目表达式)
selector?if-true-expression:if-false-expression

根据UID判断用户是系统用户还是普通用户

[root@client_1 ~]# awk -F: '{$3>=1000?usertype="Common user":usertype="System user";printf "%-20s:%20s\n",$1,usertype}' /etc/passwd
root                :         System user
bin                 :         System user
daemon              :         System user
adm                 :         System user
lp                  :         System user
...
nfsnobody           :         Common user

4.5、PATTERN

PATTERN:根据pattern条件,过滤匹配的行,再做处理
(1)如果未指定:空模式,匹配每一行
(2) /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来

#过滤以UUID开头的行
[root@client_1 ~]# awk '/^UUID/' /etc/fstab
UUID=9f1ee330-7b0f-4c5f-98e2-64662d483664 /boot                   xfs     defaults        0 0
#不是以UUID开头的行
[root@client_1 ~]# awk '!/^UUID/' /etc/fstab

#
# /etc/fstab
# Created by anaconda on Sun Feb  2 16:13:20 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0

(3) relational expression: 关系表达式,结果为“真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值

 示例:

awk -F: 'i=1;j=1{print i,j}' /etc/passwd
awk ‘!0’ /etc/passwd ; awk ‘!1’ /etc/passwd
Awk -F: '$3>=1000{print $1,$3}' /etc/passwd
awk -F: '$3<1000{print $1,$3}' /etc/passwd
awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
#当过滤条件为0时,代表为假,所以无内容
[root@client_1 ~]# awk -v i=0 'i' /etc/passwd

[root@client_1 ~]# awk -v i="0" 'i' /etc/passwd

[root@client_1 ~]# awk -v i=1 'i' /etc/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
adm:x:3:4:adm:/var/adm:/sbin/nologin
...

查看磁盘空间使用以/dev/sd开头的信息,并显示其尺寸

[root@client_1 ~]# df -h
Filesystem               Size  Used Avail Use% Mounted on
devtmpfs                 470M     0  470M   0% /dev
tmpfs                    487M     0  487M   0% /dev/shm
tmpfs                    487M  8.3M  478M   2% /run
tmpfs                    487M     0  487M   0% /sys/fs/cgroup
/dev/mapper/centos-root   17G  4.0G   14G  24% /
/dev/sda1               1014M  171M  844M  17% /boot
tmpfs                     98M   12K   98M   1% /run/user/42
tmpfs                     98M     0   98M   0% /run/user/0
[root@client_1 ~]# df |awk -F " +|%" '/^\/dev\/sd/{print $1,$5}'
/dev/sda1 17

获取处于连接状态下,远程服务器的IP

[root@client_1 ~]# ss -nt
State       Recv-Q Send-Q                                                           Local Address:Port                                                                          Peer Address:Port              
ESTAB       0      52                                                               192.168.0.101:22                                                                           192.168.0.106:60850              
[root@client_1 ~]# ss -nt | awk -F" +|:" '/^ESTAB/{print $(NF-2)}' |sort |uniq -c|sort -nr
      1 192.168.0.106

为什么会显示如下结果呢?因为i=1 后面默认隐藏了 {print $0}

[root@client_1 ~]# awk -F: 'i=1;j=1{print i,j}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
1 1
bin:x:1:1:bin:/bin:/sbin/nologin
1 1
daemon:x:2:2:daemon:/sbin:/sbin/nologin
1 1
adm:x:3:4:adm:/var/adm:/sbin/nologin
1 1

第一行 root行被过滤掉了,因为i初始值为空,所以从第二行开始

[root@client_1 ~]# awk -F: 'i++' /etc/passwd 
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
....

同理

[root@client_1 ~]# seq 10 | awk 'i++'
2
3
4
5
6
7
8
9
10

取奇数

[root@client_1 ~]# seq 10 | awk 'i=!i'
1
3
5
7
9

(4) line ranges:行范围

查找/etc/passwd中以b开头的行到f开头的行 之间的内容

[root@client_1 ~]# awk '/^b/,/^f/' /etc/passwd
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
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

Note:上述有个问题,就是如果有多段匹配,就都会找出来

[root@client_1 ~]# awk '/^s/,/^f/' /etc/passwd
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
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
libstoragemgmt:x:998:996:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
colord:x:997:995:User for colord:/var/lib/colord:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
saslauth:x:996:76:Saslauthd user:/run/saslauthd:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
setroubleshoot:x:995:992::/var/lib/setroubleshoot:/sbin/nologin
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
gluster:x:994:991:GlusterFS daemons:/run/gluster:/sbin/nologin
chrony:x:993:990::/var/lib/chrony:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
unbound:x:992:989:Unbound DNS resolver:/etc/unbound:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
geoclue:x:991:987:User for geoclue:/var/lib/geoclue:/sbin/nologin
pulse:x:171:171:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
saned:x:990:984:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:989:983::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
xulx:x:1000:1000:xulx:/home/xulx:/bin/bash

查找s开头到f开头之间的内容,当首次查找到s-f的内容后,会继续往下查找 符合条件的行。但是如果匹配到s行后,一直查到最后都没找到f开头的行作为结尾。那么这之间所有的行都会被显示,也就发生了上面的现象。

(5) BEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次

#获取当前系统用户及其uid
[root@client_1 ~]# awk -F ":" 'BEGIN{print "user","uid"}{print $1,$3}' /etc/passwd
user uid
root 0
bin 1
daemon 2
adm 3
lp 4
...

4.6、控制语句

awk控制语句

用if实现输出奇数行

[root@client_1 ~]# seq 10 | awk '{if(NR%2==1){print $0}}'
1
3
5
7
9
[root@client_1 ~]# seq 10 | awk '{if(NR%2==1){print "奇数行"}else {print "偶数行"}}'
奇数行
偶数行
奇数行
偶数行
奇数行
偶数行
奇数行
偶数行
奇数行
偶数行

过滤出/dev/sd的分区系统中,磁盘空间适用超过10%的

[root@client_1 ~]# df -h | awk -F " +|%" '/^\/dev\/sd/{if($5>10)print $1,$5}'
/dev/sda1 17

while循环

统计字符串个数

[root@client_1 ~]# awk '/linux16/' /boot/grub2/grub.cfg 
	linux16 /vmlinuz-3.10.0-1062.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8
	linux16 /vmlinuz-0-rescue-99e2e8e857a640ab8c9eb6ce1785138f root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet
[root@client_1 ~]# awk '/linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /boot/grub2/grub.cfg 
linux16 7
/vmlinuz-3.10.0-1062.el7.x86_64 31
root=/dev/mapper/centos-root 28
ro 2
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-99e2e8e857a640ab8c9eb6ce1785138f 50
root=/dev/mapper/centos-root 28
ro 2
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
rhgb 4
quiet 5

for循环

计算1到100的和

#awk while循环
[root@client_1 ~]# awk 'BEGIN{i=1;sum=0;while(i<=100){sum=sum+i;i++};print sum}'
5050
#awk for循环
[root@client_1 ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum=sum+i};print sum}'
5050
#shell循环
[root@client_1 ~]# sum=0;for((i=1;i<100;i++));do let sum+=i;done;echo $sum
4950
#seq计算,-s是指定分隔符,指定了分隔符为+。然后通过bc计算
[root@client_1 ~]# seq -s+ 100 |bc
5050

计算时间对比,awk效率最高,shell效率最低

[root@client_1 ~]# time (sum=0;for((i=1;i<100000;i++));do let sum+=i;done;echo $sum)
4999950000

real	0m0.768s
user	0m0.713s
sys	0m0.053s

[root@client_1 ~]# time (seq -s+ 100000 |bc)
5000050000

real	0m0.057s
user	0m0.047s
sys	0m0.010s

[root@client_1 ~]# time awk 'BEGIN{sum=0;for(i=1;i<=100000;i++){sum=sum+i};print sum}'
5000050000

real	0m0.020s
user	0m0.018s
sys	0m0.002s

continue,跳过本次循环

break,结束循环

next,提前结束对本行处理而直接进入下一行处理(awk自身循环)

awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
#continue,跳过本次循环
[root@client_1 ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
2500
#break,跳出循环
[root@client_1 ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}'
2145

switch语句

语法:switch(expression) {case VALUE1 or /REGEXP/: statement1; case
VALUE2 or /REGEXP2/: statement2; …; default: statementn}

[root@client_1 ~]# cat /etc/fstab 

#
# /etc/fstab
# Created by anaconda on Sun Feb  2 16:13:20 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=9f1ee330-7b0f-4c5f-98e2-64662d483664 /boot                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0
[root@client_1 ~]# awk '!/^#/{switch($3) { case "xfs":print "i am xfs" ; case "ext4":print "i am ext4";default : print "unknown"; }}' /etc/fstab
unknown
i am xfs
i am ext4
unknown
i am xfs
i am ext4
unknown
unknown

4.7、awk数组

关联数组:array[index-expression]
index-expression:
• (1) 可使用任意字符串;字符串要使用双引号括起来
• (2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值
初始化为“空串”
• (3) 若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历

举例

创建数组

[root@client_1 ~]# awk 'BEGIN{test["a"]="aaa";test["b"]="bbb";print test["a"]}'
aaa

Note:上面awk数组不灵活,必须要先知道下标,如果想要灵活遍历,就需要使用for循环

awk数组实现去重

a[$0]++,增加下标为$0的数组元素的个数,!a[$0]++会先根据a[$0]的值取反,然后才会++

[root@client_1 ~]# cat awk.txt 
aa
bb
cc
dd
aa
dd
[root@client_1 ~]# awk '!a[$0]++' awk.txt 
aa
bb
cc
dd

遍历数组

[root@client_1 ~]# awk 'BEGIN{test["a"]="aaa";test["b"]="bbb";for(i in test){print i,test[i]}}'
a aaa
b bbb

获取文件指定信息列,并添加到文件

[root@client_1 ~]# cat awk.txt 
1 aa.test.com
2 bb.test.com
3 cc.test.com
4 dd.test.cm
[root@client_1 ~]# awk -F "[ .]" '{print $2}' awk.txt
aa
bb
cc
dd
[root@client_1 ~]# awk -F "[ .]" '{print $2}' awk.txt >>awk.txt 
[root@client_1 ~]# cat awk.txt 
1 aa.test.com
2 bb.test.com
3 cc.test.com
4 dd.test.cm
aa
bb
cc
dd

#获取最大值与最小值

[root@client_1 ~]# cat awk.txt 
123,342,1131,32,56,78,1313,333,65,73,223,666
[root@client_1 ~]# awk -F "," '{max=$i;min=$i;for(i=1;i<=NF;i++){if(max<$i){max=$i}else if(min>$i){min=$i}}}END{print "min="min,"max="max}' awk.txt 
min=32 max=1313

#求男女平均分数

[root@client_1 ~]# cat awk.txt 
name gender score
a m 100
b f 99
c m 98
d f 97
e m 96

[root@client_1 ~]# awk 'NR!=1{sum[$2]+=$3;num[$2]++}END{for(i in sum){print i,sum[i]/num[i]}}' awk.txt 
m 98
f 98

4.8、awk函数

数值处理:
rand():返回0和1之间一个随机数
awk ‘BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }’
length([s]):返回指定字符串的长度
• sub(r,s,[t]):对t字符串搜索r表示模式匹配的内容,并将第一个匹配内容替换为s

echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
echo "2008:08:08 08:08:08" | awk '{sub(/:/,"-",$1);print $0}'

• gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表
示的内容

echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'
echo "2008:08:08 08:08:08" | awk '{gsub(/:/,"-",$0);print $0}'

• split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所
表示的数组中,第一个索引值为1,第二个索引值为2,…

netstat -tn | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}’

举例

rand():函数本身并不随机,只是生成随机数的种子

[root@client_1 ~]# awk 'BEGIN{print rand()}'
0.237788
[root@client_1 ~]# awk 'BEGIN{print rand()}'
0.237788
[root@client_1 ~]# awk 'BEGIN{print rand()}'
0.237788

要想生成随机数,需要结合srand()函数使用

#生成0到1之间的随机数
[root@client_1 ~]# awk 'BEGIN{srand();print rand()}'
0.177516
[root@client_1 ~]# awk 'BEGIN{srand();print rand()}'
0.199206

生成1到100的整数

[root@client_1 ~]# awk 'BEGIN{srand();print int(rand()*100)}'
79
[root@client_1 ~]# awk 'BEGIN{srand();print int(rand()*100)}'
92
[root@client_1 ~]# awk 'BEGIN{srand();print int(rand()*100)}'
16
[root@client_1 ~]# awk 'BEGIN{srand();print int(rand()*100)}'
3

awk中自定义函数

[root@client_1 ~]# cat fun.awk 
function max(x,y) {
x>y?var=x:var=y
return var
}
BEGIN{a=3;b=2;print max(a,b)}
[root@client_1 ~]# awk -f fun.awk 
3

4.9、awk中调用shell命令

[root@client_1 ~]# awk 'BEGIN{system("hostname")}'
client_1
[root@client_1 ~]# awk 'BEGIN{system("echo name")}'
name

4.10、awk脚本

将awk程序写成脚本,直接调用或执行
示例:

cat f1.awk
{if($3>=1000)print $1,$3}
awk -F: -f f1.awk /etc/passwd
cat f2.awk
#!/bin/awk –f
#this is a awk script
{if($3>=1000)print $1,$3}
chmod +x f2.awk
f2.awk –F: /etc/passwd

向awk脚本传递参数
格式:
awkfile var=value var2=value2… Inputfile
注意:在BEGIN过程中不可用。直到首行输入完成以后,变量才可用。可以通
过-v 参数,让awk在执行BEGIN之前得到变量的值。命令行中每一个指定的变
量都需要一个-v参数
示例:

cat test.awk
#!/bin/awk –f
{if($3 >=min && $3<=max)print $1,$3}
chmod +x test.awk
test.awk -F: min=100 max=200 /etc/passwd

over.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值