3.3.3 AWK基础

本文基于gawk编写

awk的基础用法

    语法:awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file

BEGIN 语句块在 awk 开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在 BEGIN 语句块中。

END 语句块在 awk 从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在 END 语句块中完成,它也是一个可选语句块。

pattern 语句块中的通用命令是最重要的部分,也是可选的。如果没有提供 pattern 语句块,则默认执行{ print },即打印每一个读取到的行,awk 读取的每一行都会执行该语句块。

-F 指明输入时用到的字段分隔符
-v var=value: 自定义变量

-f 从指定文件中读取AWK程序

    AWK中也有许多内置变量

FS:输入字段分隔符,默认为空白字符

[root@CentOS7 bin]# awk -v FS=':' '{print$1FS$3}' /etc/passwd  #FS是变量,所以可以在后面的awk程序中引用
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
...

OFS:输出字段分隔符,默认为空白字符

[root@CentOS7 bin]# df | awk -v OFS=':' '{print $1,$5}'
Filesystem:Use%
/dev/sda2:8%
devtmpfs:0%
tmpfs:0%
tmpfs:2%
tmpfs:0%
/dev/sda5:1%
/dev/sda1:16%
tmpfs:0%

RS:输入记录分隔符,指定输入时的换行符

[root@CentOS7 bin]# df | awk -v RS='%' '{print $0}'
Filesystem     1K-blocks    Used Available Use
 Mounted on
/dev/sda2       52403200 3745008  48658192   8
 /
devtmpfs          750372       0    750372   0
 /dev
tmpfs             765076       0    765076   0
 /dev/shm
tmpfs             765076    9180    755896   2
 /run
tmpfs             765076       0    765076   0
 /sys/fs/cgroup
/dev/sda5       20961280   93604  20867676   1
 /data
/dev/sda1        1038336  161544    876792  16
 /boot
tmpfs             153016       0    153016   0
 /run/user/0

ORS:输出记录分隔符,输出时用指定符号代替换行符

[root@CentOS7 bin]# ps | awk -v ORS='---' '{print $0}'
   PID TTY          TIME CMD---  1335 pts/1    00:00:00 bash---  9938 pts/1    00:00:00 ps---  9939 pts/1    00:00:00 awk---

NF:字段数量

[root@CentOS7 bin]# awk '{print NF,$NF}' /etc/fstab    #NF是内置变量,不用加$符号,但是引用第NF个字符需要写$
0 
1 #
2 /etc/fstab
10 2018
1 #
9 '/dev/disk'
12 info
1 #
6 0
6 0
6 0
6 0

NR:记录号

[root@CentOS7 bin]# awk '{print NR,$0}END{print NR}' /etc/fstab 
1 
2 #
3 # /etc/fstab
4 # Created by anaconda on Mon May  7 02:06:31 2018
5 #
6 # Accessible filesystems, by reference, are maintained under '/dev/disk'
7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
8 #
9 UUID=a476d3a0-5f14-476e-be7e-444dfd336b2d /                       xfs     defaults        0 0
10 UUID=7c3a1d3e-0307-4e0c-ab81-48fef9afb8b5 /boot                   xfs     defaults        0 0
11 UUID=d43b008e-4320-42a0-9376-a89ca74691d3 /data                   xfs     defaults        0 0
12 UUID=3be8497e-f039-4bf0-acbc-ea5783e314b4 swap                    swap    defaults        0 0
12

FNR:各文件分别计数,记录号

[root@CentOS7 bin]# awk '{print FNR,$0}' /etc/fstab /etc/inittab 
1 
2 #
3 # /etc/fstab
4 # Created by anaconda on Mon May  7 02:06:31 2018
5 #
6 # Accessible filesystems, by reference, are maintained under '/dev/disk'
7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
8 #
9 UUID=a476d3a0-5f14-476e-be7e-444dfd336b2d /                       xfs     defaults        0 0
10 UUID=7c3a1d3e-0307-4e0c-ab81-48fef9afb8b5 /boot                   xfs     defaults        0 0
11 UUID=d43b008e-4320-42a0-9376-a89ca74691d3 /data                   xfs     defaults        0 0
12 UUID=3be8497e-f039-4bf0-acbc-ea5783e314b4 swap                    swap    defaults        0 0
1 # inittab is no longer used when using systemd.
2 #
3 # ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
4 #
5 # Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target
6 #
7 # systemd uses 'targets' instead of runlevels. By default, there are two main targets:
8 #
9 # multi-user.target: analogous to runlevel 3
10 # graphical.target: analogous to runlevel 5
11 #
12 # To view current default target, run:
13 # systemctl get-default
14 #
15 # To set a default target, run:
16 # systemctl set-default TARGET.target
17 #

FILENAME:当前文件名

[root@CentOS7 bin]# awk '{print FILENAME,$0}' /etc/fstab
/etc/fstab 
/etc/fstab #
/etc/fstab # /etc/fstab
/etc/fstab # Created by anaconda on Mon May  7 02:06:31 2018
/etc/fstab #
/etc/fstab # Accessible filesystems, by reference, are maintained under '/dev/disk'
/etc/fstab # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
/etc/fstab #
/etc/fstab UUID=a476d3a0-5f14-476e-be7e-444dfd336b2d /                       xfs     defaults        0 0
/etc/fstab UUID=7c3a1d3e-0307-4e0c-ab81-48fef9afb8b5 /boot                   xfs     defaults        0 0
/etc/fstab UUID=d43b008e-4320-42a0-9376-a89ca74691d3 /data                   xfs     defaults        0 0
/etc/fstab UUID=3be8497e-f039-4bf0-acbc-ea5783e314b4 swap                    swap    defaults        0 0

ARGC:命令行参数的个数

[root@CentOS7 bin]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/inittab /etc/passwd
4

ARGV:数组,保存的是命令行所给定的各参数

[root@CentOS7 bin]# awk 'BEGIN{print ARGC}END{print ARGV[0],ARGV[1],ARGV[2],ARGV[3]}' /etc/fstab /etc/inittab /etc/passwd
4
awk /etc/fstab /etc/inittab /etc/passwd

AWK中的变量

    AWK 程序中的变量分为两种:自定义变量与内置变量

自定义变量分为两种,在选项中使用 -v 声明的在整个 AWK 程序中都生效;

                                  在 program 中直接定义的只在当前 program 中生效。

[root@CentOS7 bin]# awk -v test1="Linux" 'BEGIN{test2="CentOS";print test1,test2}END{print test1,test2}' /etc/fstab
Linux CentOS
Linux

printf命令

    printf 命令用于格式化输出,每个格式与后面的每个条目一一对应,在输出后不添加\n并不会自动换行。

    语法:printf "格式" ,条目1,条目2...

[root@CentOS7 bin]# awk -v test=12345.6789 'BEGIN{printf "%13.2f\t---\n",test}'
     12345.68	---

    格式符

%c: 显示字符的 ASCII 码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数

%%: 显示%自身

    修饰符

#.#:%5d 表示字符最短占3个字符,%3.1f 表示占三位,保留小数点后1位。 
-: 左对齐(默认右对齐) %-15s
+:显示数值的正负符号 %+d

操作符

    算术操作符:+、-、*、/、%、^

    赋值操作符:=、+=、-=、*=、/=、^=、++、--

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

    匹配操作符:~、!~

    逻辑操作符:&&、||、!、?

AWK模式

    模式:根据 pattern 条件,过滤匹配的行,再做处理

未指定:空模式,匹配每一行

/regular expression/:仅处理能够模式匹配到的行,需要用 / / 括起来

[root@CentOS7 bin]# awk '/^root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

行范围可以使用 /模式1/,/模式2 / 来指定,也可以用 NR 配合操作符来指定

[root@CentOS7 bin]# awk '(NR>=10&&NR<=20){print}' /etc/passwd
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
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
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
libstoragemgmt:x:998:997:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
colord:x:997:996:User for colord:/var/lib/colord:/sbin/nologin

AWK控制语句

    if-else

    语法:if (判断条件1) {语句1} [ else if (判断条件2) {语句2} else {语句3} ]

    范例:根据 UID 区分 passwd 文件中用户的类型

[root@CentOS7 ~]# getent passwd | awk -v FS=: -v OFS='>>>' '{if($3>=1000)printf "Common User: %s\n",$1;else printf "System User: %-s\n",$1}'
System User: root
System User: bin
System User: daemon
System User: adm
System User: lp
System User: sync
System User: shutdown
System User: halt
System User: mail
System User: operator
System User: games
System User: ftp
System User: nobody
System User: systemd-network
System User: dbus
System User: polkitd
System User: abrt
...

    switch

    语法:switch (变量){case PAT1:语句1;case PAT2:语句2;...;default:语句}

[root@CentOS7 ~]#⮀awk -v test=5 'BEGIN{switch(test+1){case 5:{print "aaa";break} ;case 6:{print "ture";break} ;case 7:{print "bbb";break}}}'
ture

注意:1.CentOS6 上不支持使用 switch 2.case 与 PAT 之间必须有空格 3.与C语言一样,switch 拥有穿透效果,所以使用时记得在语句后加 break

    while

    语法:while(循环条件){循环语句}

    范例:判断 grub.conf 文件中,开机是否启用 selinux ,开启的话关闭
[root@CentOS6 ~]# awk '/^[[:space:]]*kernel/ {while(i<=NR){if($i=="selinux=0"){print $i;next}else i++};{printf "%s selinux=0\n",$0}}' /boot/grub/grub.conf 
selinux=0

    for

    语法:for(初始值;循环条件;变量修正){循环体}

    范例:计算1到10000累加

[root@CentOS6 ~]# awk 'BEGIN{sum=0;for(i=0;i<=10000;i++){sum+=i;};print sum}'
50005000

    根据实验,使用 awk 计算效率最高,使用 bc 命令次之,再者是 for 循环,最后是 for-in 语句

    break、continue、next

    break [N]:跳出第 N 层循环,默认为当前循环。
    continue [N]:跳过第 N 层的本轮循环,默认为当前循环。
    next:跳出 awk 对本行处理。

AWK数组

    awk中数组只能同时默认使用关联数组。如果脚标是字符串的话,需要用引号引起来。

    遍历数组

    语法:for (变量 in 数组名) {循环体}

    for 循环中每次循环数组都会将一个脚标赋值给变量,所以在循环体中,可以通过引用“数组名 [变量]”来对数组进行遍历。

[root@CentOS7 data]# awk '{!arr[$0]++;print $0,arr[$0]}' /data/test.txt 
ture 1
bbb 1
ture 2
bbb 2
ture 3
bbb 3
ture 4
bbb 4
ture 5
bbb 5
ture 6
bbb 6
ture 7
bbb 7
ture 8
bbb 8
ture 9
bbb 9
ture 10
bbb 10
ture 11
bbb 11
ture 12
bbb 12
[root@CentOS7 data]# awk '!arr[$0]++' /data/test.txt    #先进行算术计算,再进行逻辑运算,实现了sort -u 的功能
ture
bbb

AWK函数

    数值处理

rand():返回0和1之间一个随机数

[root@CentOS7 data]# awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'  #不使用srand()函数每次生成的随机数不变
86
18
8
10
60
47
92
24
92
31

srand( [Expr]):将 rand 函数的种子值设置为 Expr 参数的值,或如果省略 Expr 参数则使用某天的时间。返回先前的种子值。
atan2( y, x ) 返回 y/x 的反正切。
cos( x ) 返回 x 的余弦;x 是弧度。
sin( x ) 返回 x 的正弦;x 是弧度。
exp( x ) 返回 x 幂函数。
log( x ) 返回 x 的自然对数。
sqrt( x ) 返回 x 平方根。
int( x ) 返回 x 的截断至整数的值。

    字符串处理

length [(String)]:返回 String 参数指定的字符串的长度(字符形式)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。

[root@CentOS7 data]# echo "01234 5 " | awk '{print length($0)}'    #空格也算是一个字符
8
sub(r,s,[t]):对 t 字符串进行搜索 r 表示的模式匹配的内容,并将 第一个匹配的内容替换为 s。

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

[root@CentOS7 data]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
2008-08:08 08:08:08
[root@CentOS7 data]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$0)'
2008-08:08 08:08:08
[root@CentOS7 data]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$1)'
2008-08-08 08:08:08
[root@CentOS7 data]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'
2008-08-08 08-08-08
split(String, A, [Ere]):将 String 指定的参数分割为数组元素 A[1], A[2], . . ., A[n],并返回 n 变量的值。此分隔可以通过 Ere 参数指定的扩展正则表达式进行,或用当前字段分隔符(FS 特殊变量)来进行。
netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
192.168.30.1 2
0.0.0.0 4

index(String1, String2):在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从 1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零)。

[root@CentOS7 data]# netstat -tan | awk 'index($6,"ESTABLISHED")'
tcp        0     52 192.168.30.6:22         192.168.30.1:33499      ESTABLISHED
tcp        0      0 192.168.30.6:22         192.168.30.1:33501      ESTABLISHED

    自定义函数

    语法

function 函数名 (形参1,形参2,...){
	函数体
	返回值	
}
    范例:
[root@CentOS7 bin]#⮀awk 'function max(num1,num2){num1>num2?NUM=num1:NUM=num2;return NUM} BEGIN{a=4;b=7;print max(a,b)}'
7

    调用外部命令

system(Command):执行 Command 参数指定的命令,并返回退出状态。

[root@CentOS7 bin]#⮀awk 'BEGIN{file=system("ls -l");print file}'
total 92
-rwxr-xr-x 1 root root  455 May 12 17:48 9x9table.sh
-rwxr-xr-x 1 root root 2029 May 12 11:56 chessboard.sh
-rwxr-xr-x 1 root root  637 May 14 20:30 copycmd.sh
-rwxr-xr-x 1 root root  462 May 16 11:17 Ddos.sh
-rwxr-xr-x 1 root root 1366 May 12 18:04 guess.sh
-rwxr-xr-x 1 root root  592 May 10 16:40 Hanoi_Tower.sh
-rwxr-xr-x 1 root root   67 May 17 15:07 if.sh
-rwxr-xr-x 1 root root  489 May  9 21:41 isosceles_triangle.sh
-rwxr-xr-x 1 root root  619 May 15 12:02 MageAwk.sh
-rwxr-xr-x 1 root root  688 May 15 16:15 matrix.sh
-rwxr-xr-x 1 root root  358 May 14 20:11 md5break.sh
-rwxr-xr-x 1 root root  759 May 12 14:25 mkdiruser.sh
-rwxr-xr-x 1 root root  501 May 13 17:55 Rabbit_Series1.sh
-rwxr-xr-x 1 root root  577 May 13 19:27 Rabbit_Series2.sh
-rwxr-xr-x 1 root root  105 May 12 12:42 read.sh
-rwxr-xr-x 1 root root  671 May 12 21:03 right-angled.sh
-rwxr-xr-x 1 root root  524 May 12 17:24 scanIP.sh
-rw-r--r-- 1 root root   33 May 16 11:38 score.txt
-rwxr-xr-x 1 root root  761 May 15 15:22 selinux.sh
-rwxr-xr-x 1 root root  663 May 14 19:58 sel.sh
-rwxr-xr-x 1 root root  888 May 12 15:51 Statistic_type.sh
-rwxr-xr-x 1 root root   84 May  8 17:50 sumodd.sh
-rwxr-xr-x 1 root root  210 May  9 10:00 test.sh
0                                                             #返回状态

AWK脚本

将 AWK 程序写入脚本,可以在使用时通过 -f 选项调用。但是 AWK的 sha-bang 是 #!/bin/awk -f

    范例:显示系统中的普通用户

cat common.awk
#!/bin/awk –f
#this is a awk script
{if($3>=1000)print $1,$3}

f2.awk –F: /etc/passwd



猜你喜欢

转载自blog.csdn.net/m30_miriam/article/details/80341742