awk命令说明
wk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等
命令格式和参数
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
常用命令选项
- -F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:,默认的分隔符是连续的空格或制表符
- -v var=value 赋值一个用户定义变量,将外部变量传递给awk
- -f scripfile 从脚本文件中读取awk命令
- -m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。
- $NF 代表最后一个字段
- && 与
- || 或
- FS 输入分隔符,与-F分隔符一样
- OFS 输出字段分隔符
- RS 输入记录分隔符
- $0 显示整行
- NR 内置字段,表示第几行
- 1...N 第一个字段到第N个字段,
$1表示第一个字段,$(NF-1)表示倒数第二个字段的值
awk脚本基本结构
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
awk脚本通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块3部分组成,这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被 单引号 中,例如:
awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename
总的来说,awk脚本是由模式和操作组成的
模式可以是以下任意一个:
- /正则表达式/:使用通配符的扩展集。
- 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
- 模式匹配表达式:用运算符
~(匹配)和!~(不匹配)。 - BEGIN语句块、pattern语句块、END语句块:参见awk的工作原理
操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,主要部分是:
- 变量或数组赋值
- 输出命令
- 内置函数
- 控制流语句
awk的工作原理
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
- 第一步:执行
BEGIN{ commands }语句块中的语句; - 第二步:从文件或标准输入(stdin)读取一行,然后执行
pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。 - 第三步:当读至输入流末尾时,执行
END{ commands }语句块。
BEGIN语句块 在awk开始从输入流中读取行 之前 被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块 在awk从输入流中读取完所有的行 之后 即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
pattern语句块 中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
内置函数
print : 打印
printf : 格式化打印
%s : 字符串
%d: 数字
- : 左对齐
+ : 右对齐
15 : 至少占用15字符
命令表达式和流程控制语法
比较表达式
- > : 大于
- < : 小于
- >= : 大于等于
- <= : 小于等于
- ~ : 正则匹配(包含)
- !~ : 正则匹配(不包含)
- 打印第三列 < 第四列的行
guanwu@master:~/learnshell/awk$ awk -F: '$4 > $3{print $0}' /etc/passwd | head -5
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
- 打印结尾匹配或者不匹配的行,匹配使用 ~, 不匹配使用 !~
guanwu@master:~/learnshell/awk$ awk -F: '$NF ~ /bash/{print $0}' /etc/passwd | head -5
root:x:0:0:root:/root:/bin/bash
guanwu:x:1000:1000:guanwu,,,:/home/guanwu:/bin/bash
guanwu@master:~/learnshell/awk$ awk -F: '$NF !~ /bash/{print $0}' /etc/passwd | head -5
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
- 打印第三行
guanwu@master:~/learnshell/awk$ awk -F: 'NR == 3{print $0}' /etc/passwd
bin:x:2:2:bin:/bin:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
算术表达式
- +
- -
- *
- /
- %
加法
guanwu@master:~/learnshell/awk$ awk -F: '$3 + $4 > 2000{print $0}' /etc/passwd
sync:x:4:65534:sync:/bin:/bin/sync
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
kernoops:x:113:65534:Kernel Oops Tracking Daemon,,,:/:/usr/sbin/nologin
gnome-initial-setup:x:126:65534::/run/gnome-initial-setup/:/bin/false
sshd:x:130:65534::/run/sshd:/usr/sbin/nologin
_rpc:x:131:65534::/run/rpcbind:/usr/sbin/nologin
statd:x:132:65534::/var/lib/nfs:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
乘法
guanwu@master:~/learnshell/awk$ awk -F: '$3 * $4 > 2000{print $0}' /etc/passwd | head -5
sync:x:4:65534:sync:/bin:/bin/sync
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:102:105::/nonexistent:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
取余
打印双数行, NR表示当前第几行, 使用printf格式化打印,类似c语言, %2d表示向右对齐,占两位
guanwu@master:~/learnshell/awk$ awk -F: 'NR % 2 == 0{printf("%2d %s %s\n",NR, " ", $0);}' /etc/passwd | head -5
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
4 sys:x:3:3:sys:/dev:/usr/sbin/nologin
6 games:x:5:60:games:/usr/games:/usr/sbin/nologin
8 lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
10 news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
逻辑表达式
- && 逻辑与
- || 逻辑或
- ! 逻辑非 逻辑与
guanwu@master:~/learnshell/awk$ awk -F: '$3 + $4 > 2000 && $3 * $4 > 2000{print $0}' /etc/passwd
sync:x:4:65534:sync:/bin:/bin/sync
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
kernoops:x:113:65534:Kernel Oops Tracking Daemon,,,:/:/usr/sbin/nologin
gnome-initial-setup:x:126:65534::/run/gnome-initial-setup/:/bin/false
sshd:x:130:65534::/run/sshd:/usr/sbin/nologin
_rpc:x:131:65534::/run/rpcbind:/usr/sbin/nologin
statd:x:132:65534::/var/lib/nfs:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
逻辑或
guanwu@master:~/learnshell/awk$ awk -F: '$3 + $4 > 2000 || $3 * $4 > 2000{print $0}' /etc/passwd | head -5
sync:x:4:65534:sync:/bin:/bin/sync
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:102:105::/nonexistent:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
逻辑非
guanwu@master:~/learnshell/awk$ awk -F: '! ($3 + $4 > 30){print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
控制流
if 只能出现在 BEGIN{}PATTERN{}END{} 中的PATTERN{}中的{}中,即出现在循环体中。
guanwu@master:~/learnshell/awk$ awk -F: '{if($3>$4){print $3 "大于" $4}else{print $3 "小于或等于" $4}}' /etc/passwd | head -5
0小于或等于0
1小于或等于1
2小于或等于2
3小于或等于3
4小于或等于65534
guanwu@master:~/learnshell/awk$
if 使用格式:
if(){} : 单分支
if(){}else{} : 双分支
if(){}else if(){} else{} : 多分支
for循环
每一行第一个字段打印10次
guanwu@master:~/learnshell/awk$ awk -F: '{for(i=10;i>0;i--){print NR " " $1}}' /etc/passwd | head -20
1 root
1 root
1 root
1 root
1 root
1 root
1 root
1 root
1 root
1 root
2 daemon
2 daemon
2 daemon
2 daemon
2 daemon
2 daemon
2 daemon
2 daemon
2 daemon
2 daemon
guanwu@master:~/learnshell/awk$
while循环 每一行打印10次
guanwu@master:~/learnshell/awk$ awk -F: '{i=1; while(i<=10){print NR " " $0, i++}}' /etc/passwd | head -20
1 root:x:0:0:root:/root:/bin/bash 1
1 root:x:0:0:root:/root:/bin/bash 2
1 root:x:0:0:root:/root:/bin/bash 3
1 root:x:0:0:root:/root:/bin/bash 4
1 root:x:0:0:root:/root:/bin/bash 5
1 root:x:0:0:root:/root:/bin/bash 6
1 root:x:0:0:root:/root:/bin/bash 7
1 root:x:0:0:root:/root:/bin/bash 8
1 root:x:0:0:root:/root:/bin/bash 9
1 root:x:0:0:root:/root:/bin/bash 10
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 1
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 2
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 3
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 4
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 5
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 6
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 7
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 8
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 9
2 daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 10
guanwu@master:~/learnshell/awk$
do循环
guanwu@master:~/learnshell/awk$ awk 'BEGIN{
total=0;
i=0;
do {total+=i;i++;} while(i<=100)
print total;
}'
5050
guanwu@master:~/learnshell/awk$
数组的使用
数组定义
Array[1]="sun"
Array[2]="kai"
Array["first"]="www"
Array"[last"]="name"
Array["birth"]="1987"
数组访问
{ for(item in array) {print array[item]}; } #输出的顺序是随机的
{ for(i=1;i<=len;i++) {print array[i]}; } #Len是数组的长度
获取数组的长度
guanwu@master:~/learnshell/awk$ awk 'BEGIN{info="it is a test from asia";lens=split(info,tA," ");print length(tA),lens;}'
6 6
guanwu@master:~/learnshell/awk$
对数组进行排序并输出,asort函数是排序函数,并返回数组长度
awk 'BEGIN{info="it is a test from someone";split(info,tA," ");len=asort(tA);for(k in tA){print k,tA[k],"数组长度为" len;}}'
guanwu@master:~/learnshell/awk$ awk 'BEGIN{info="it is a test from someone";split(info,tA," ");len=asort(tA);for(k in tA){print k,tA[k],"数组长度为" len;}}'
1 a 数组长度为6
2 from 数组长度为6
3 is 数组长度为6
4 it 数组长度为6
5 someone 数组长度为6
6 test 数组长度为6
guanwu@master:~/learnshell/awk$
for in输出数组
awk 'BEGIN{info="it is a test";tlen=split(info,tA," ");for(k=1;k<=tlen;k++){print k,tA[k];}}'
guanwu@master:~/learnshell/awk$ awk 'BEGIN{info="it is a test";tlen=split(info,tA," ");for(k=1;k<=tlen;k++){print k,tA[k];}}'
1 it
2 is
3 a
4 test
guanwu@master:~/learnshell/awk$
实战案例
- 选项F的使用,截取第六个字段,并使用":"分割
guanwu@master:~$ tail -l /etc/passwd | awk -F ":" '{print $6}'
/var/lib/geoclue
/run/pulse
/run/gnome-initial-setup/
/run/hplip
/var/lib/gdm3
/home/guanwu
/var/lib/redis
/run/sshd
/run/rpcbind
/var/lib/nfs
guanwu@master:~$
打印最后一列的值, NF表示列的字段数量,$NF表示NF列的字段的值
guanwu@master:~/learnshell/awk$ awk -F ':' '{print $NF}' /etc/passwd |tail -10
/usr/sbin/nologin
/usr/sbin/nologin
/bin/false
/bin/false
/bin/false
/bin/bash
/usr/sbin/nologin
/usr/sbin/nologin
/usr/sbin/nologin
/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
- -v的使用 统计某列的和
guanwu@master:~/learnshell/awk$ cat test_sum.txt
1
2
3
4
5
6
7
8
9
10
guanwu@master:~/learnshell/awk$ awk -v "a=0" '{a+=$1;print a}' test_sum.txt | tail -1
55
传递外部的值
guanwu@master:~/learnshell/awk$ VAR=10000
guanwu@master:~/learnshell/awk$ echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
10000
guanwu@master:~/learnshell/awk$
- -OFS的使用,指定分隔符并打印
guanwu@master:~/learnshell/awk$ awk -F: 'BEGIN{OFS=" >>> "}{print $NF, $1}' /etc/passwd | tail -5
/bin/bash >>> guanwu
/usr/sbin/nologin >>> redis
/usr/sbin/nologin >>> sshd
/usr/sbin/nologin >>> _rpc
/usr/sbin/nologin >>> statd
guanwu@master:~/learnshell/awk$
4.END的使用
打印最后一行
awk 'END{print $0}' /etc/passwd
guanwu@master:~/learnshell/awk$ awk 'END{print $0}' /etc/passwd
statd:x:132:65534::/var/lib/nfs:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
打印最后一行的字段数
- 函数的使用
4.1 格式化打印
awk -F: 'BEGIN{OFS=" | "}{printf "|%+15s|%-15s|\n", $NF, $1}'
%+15s表示向右对其, %-15s表示向左对其,以 | 为分隔符
guanwu@master:~/learnshell/awk$ awk -F: 'BEGIN{OFS=" | "}{printf "|%+15s|%-15s|\n", $NF, $1}' /etc/passwd | tail -5
| /bin/bash|guanwu |
|/usr/sbin/nologin|redis |
|/usr/sbin/nologin|sshd |
|/usr/sbin/nologin|_rpc |
|/usr/sbin/nologin|statd |
guanwu@master:~/learnshell/awk$
- 选行 打印第44行
guanwu@master:~/learnshell/awk$ awk NR==44'{print $0}' /etc/passwd
pulse:x:125:132:PulseAudio daemon,,,:/run/pulse:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$
统计文件的行数
guanwu@master:~/learnshell/awk$ awk 'END{print NR}' test_sum.txt
10
- 定位
6.1 匹配以root开始的行
guanwu@master:~/learnshell/awk$ awk -F: '/^root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
guanwu@master:~/learnshell/awk$
使用match函数正则匹配
guanwu@master:~/learnshell/awk$ awk 'BEGIN{info="this is a test2024test!";print match(info,/[0-9]+/)?"ok":"no found";}'
ok
guanwu@master:~/learnshell/awk$
- 流程 隔五行打印一条直线
awk -F: '{if(NR%5==0){print "----------"}print $0}' /etc/passwd | head -20
guanwu@master:~/learnshell/awk$ awk -F: '{if(NR%5==0){print "----------"}print $0}' /etc/passwd | head -20
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
----------
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
----------
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
----------
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
guanwu@master:~/learnshell/awk$