本文基于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(循环条件){循环语句}
[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