awk介绍
- AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一
- 这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯、彼得·温伯格和布莱恩·柯林汉姓氏的首个字母)的最大功能取决于一个人所拥有的知识
- AWK(Aho、Weinberger、Kernighan) ,报告生成器,简单的来说就是打报表,格式化文本输出
- 它具备了一个完整的语言所应具有的几乎所有精美特性
- 实际上AWK的确拥有自己的语言:AWK程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”
- AWK版本还特别多;New AWK (nawk), GNU AWK (gawk),当然我们用的是GAWK,属于GNU项目
awk基本用法
awk报告生成器,格式化输出文本文件
-
awk基本语法格式
- awk [options] ‘program’ var=value file…
- awk [options] -f programfile var=value file…
- awk [options] 'BEGIN{ action;… } pattern{ action;… } END
- action;… }' file ...
optinos
表示可选的命令行选项prgoram
awk语句var=value
自己定义变量file....
处理文本文件programfile
调用程序文件program
通常是被单引号或双引号中,建议用单引号,双引号在后面有其他用途
-
awk程序
- awk 程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成
-
awk选项
- -F: 指明输入时用到的字段分隔符
[root@localhost ~]# awk -F: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
systemd-bus-proxy
systemd-network
dbus
polkitd
colord
abrt
libstoragemgmt
rpc
- -v :var=value: 自定义变量
[root@localhost ~]# awk -v RS=':' '{print }' /etc/passwd
root
x
0
0
root
/root
/bin/bash
bin
x
1
1
bin
/bin
/sbin/nologin
daemon
x
2
2
daemon
/sbin
awk语言
- 基本格式:awk [options] 'program' file…
- program:pattern{action statements;..}
- pattern和action:
- pattern:部分决定动作语句何时触发及触发事件
- BEGIN:相当于处理文件内容之前执行的一个语句,用于打印标题
- END:
- action statements:对数据进行处理,如统计、汇总等
- 分割符、域和记录
- awk在执行时,由分割符来分割字段,可以用冒号或者斜线等等要看自己的指定
- 切割完已后那就是一个字段,可以说是局部变量
$1
、$2
...... 用awk自己来调用,不用自己声明,有一个需要注意$0
就是所有字段或所有列 - 选项-F就是用来指定分割符的
- 域的意思就是已经被切割完的字符,也可以称呼为列或字段等,比如说第一行就用$1他会把一列全打印显示处理
- 记录就是说一行就是一条记录,怎么去区分行一行或几行,那就是分割符,分割符要看自己来指定千万别记太死
- 默认空格为换行符,但是其他的换行符需要自己指定
awk工作原理
- 第一步:执行BEGIN{action;… }语句块中的语句
- 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕
- 第三步:当读至输入流末尾时,执行END{action;…}语句块
- BEGIN:这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句
- END: 这也是一个科学的语句块,比如打印所有行的分析结果等信息汇总或awk输入流读取完所有信息将会执行END
- pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
AWK是默认读取标准输入的命令
读取多少行就打印多少行,用文件输入或手动输入都可以
-
要点:
- 逗号分隔符
- 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式
- 如省略item,相当于print $0
示例
[root@localhost ~]# awk '{print "hello,awk"}' /etc/passwd
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
hello,awk
- 在输出的时候,打印的内容必须要以
,
号隔开不然会合并在一起
[root@localhost ~]# awk -F: '{print $1$4}' /etc/passwd
root0
bin1
daemon2
adm4
lp7
sync0
shutdown0
halt0
mail12
operator0
games100
ftp50
nobody99
systemd-bus-proxy997
systemd-network192
dbus81
polkitd996
colord995
abrt173
- 如果用
,
号将会分割开
[root@localhost ~]# awk -F: '{print $1,$4}' /etc/passwd
root 0
bin 1
daemon 2
adm 4
lp 7
sync 0
shutdown 0
halt 0
mail 12
operator 0
games 100
ftp 50
nobody 99
systemd-bus-proxy 997
systemd-network 192
dbus 81
polkitd 996
colord 995
abrt 173
- 如果你想用别的符号来分割你可以补上,中间加的是字符串哦,别搞混了
[root@localhost ~]# awk -F: '{print $1"===="$4}' /etc/passwd
root====0
bin====1
daemon====2
adm====4
lp====7
sync====0
shutdown====0
halt====0
mail====12
operator====0
games====100
ftp====50
nobody====99
systemd-bus-proxy====997
systemd-network====192
dbus====81
polkitd====996
colord====995
abrt====173
- 注意我们现在用的是变量不用加双引号,如果是字符串必须要加双引号,不然会这样
[root@localhost ~]# awk -F: '{print $1====$4}' /etc/passwd
awk: cmd. line:1: {print $1====$4}
awk: cmd. line:1: ^ syntax error
- 那如果我想取磁盘利于分区利用率怎么取,可以这样
[root@localhost ~]# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 41922560 385320 41537240 1% /
devtmpfs 2008832 0 2008832 0% /dev
tmpfs 2023456 0 2023456 0% /dev/shm
tmpfs 2023456 8772 2014684 1% /run
tmpfs 2023456 0 2023456 0% /sys/fs/cgroup
/dev/sda3 20961280 2679012 18282268 13% /usr
/dev/sda1 508580 148756 359824 30% /boot
tmpfs 404692 0 404692 0% /run/user/0
[root@localhost ~]# df|awk '{print $5}'
Use%
1%
0%
0%
1%
0%
13%
30%
0%
- 如果我只想要数值,不想要符号,或我只想要分区的数值,怎么取,我们可以配合
grep
[root@localhost ~]# df|grep '^/dev/sd'|awk '{print $5}'|awk -F% '{print $1 }'
1
13
30
- 如果你什么都不写会产生什么后果,那就相当打印
$0
[root@localhost ~]# awk '{print }' /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
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
nobody:x:99:99:Nobody:/:/sbin/nologin
- 格式输出的时候变量一定要一个一个的打印如
[root@localhost ~]# awk -F: '{print $1,$5,$3}' /etc/passwd
root root 0
bin bin 1
daemon daemon 2
adm adm 3
lp lp 4
sync sync 5
shutdown shutdown 6
halt halt 7
mail mail 8
operator operator 11
games games 12
ftp FTP User 14
nobody Nobody 99
- 不能这样填写变量
[root@localhost ~]# awk -F: '{print $1-3}' /etc/passwd
-3
-3
-3
-3
-3
-3
-3
-3
-3
-3
-3
-3
-3
- 如果你想对其你可以加一个或多个TAB键,但是他是个字符串必须要加双引号
[root@localhost ~]# awk -F: '{print $1"\t\t\t"$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
awk变量
- 在awk里面也支持内置变量和自定义变量
内置变量
- 内置变量
- FS:输入字段分割符,默认为空白字符
- FS是个变量需要赋值,功能和-F一样
[root@localhost ~]# awk -v FS=: '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp
nobody
- 还可以引用变量
[root@localhost ~]# awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
root : 0
bin : 1
daemon : 2
adm : 3
lp : 4
sync : 5
shutdown : 6
halt : 7
mail : 8
operator : 11
games : 12
ftp : 14
nobody : 99
- OFS:输出字段分割符,默认为空白字符
[root@localhost ~]# awk -F: -v OFS='-' '{print $1,$3}' /etc/passwd
root-0
bin-1
daemon-2
adm-3
lp-4
sync-5
shutdown-6
halt-7
mail-8
operator-11
games-12
ftp-14
- RS:输入记录分割符,指定输入时的换行符,原换行符仍有效
[root@localhost ~]# awk -v RS=' ' '{print }' /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
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
- ORS:输出记录分隔符,输出时用指定符号代替换行符
[root@localhost ~]# awk -F: -v ORS="---" '{print $1}' /etc/passwd
root---bin---daemon---adm---lp---sync---shutdown---halt---mail---operator---games---ftp---nobody---systemd-bus-proxy---systemd-network---dbus---polkitd---colord---abrt---libstoragemgmt---rpc---setroubleshoot---rtkit---usbmuxd---tss---geoclue---chrony---mysql---pulse---gdm---rpcuser---nfsnobody---postfix---ntp---ssh
- NF:字段数量,表示一共有7个字段
[root@localhost ~]# awk -F: 'END{print NF}' /etc/passwd
7
- NR :行号
[root@localhost ~]# awk -F: '{print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator
11 games
12 ftp
13 nobody
14 systemd-bus-proxy
15 systemd-network
16 dbus
17 polkitd
18 colord
19 abrt
- FNR: 各个文件分别计数,行号
[root@localhost ~]# awk '{print FNR,$0}' /etc/issue /etc/fstab
1 \S
2 Kernel \r on an \m
3
4 Mage Education Learning Services
5 http://www.magedu.com
6
1
2 #
3 # /etc/fstab
4 # Created by anaconda on Thu Jul 13 08:26:25 2017
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 #
- FILENAME:当前文件名
[root@localhost ~]# awk -F: '{print FILENAME,$0}' /etc/issue
/etc/issue \S
/etc/issue Kernel \r on an \m
/etc/issue
/etc/issue Mage Education Learning Services
/etc/issue http://www.magedu.com
/etc/issue
- ARGC:命令行参数的个数
[root@localhost ~]# awk -F: '{print ARGC}' /etc/passwd /etc/issue /etc/fstab
4
4
4
4
4
4
4
4
4
- ARGV:数组,保存的是命令行所给定的各参数
[root@localhost ~]# awk -F: '{print ARGC,ARGV[0]}' /etc/passwd /etc/issue /etc/fstab
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
4 awk
变量名 | 属性 |
---|---|
$0 |
当前记录 |
$1~$n |
当前记录的第n个字段 |
FS | 输入只读分割符 默认的是空格 |
RS | 输入记录分割符 默认为换行符 |
NF | 当前记录中的字段个数,就是有多少列 |
NR | 已经独处的记录数,就是行号,从1开始 |
OFS | 输出字段分割符 默认也是空格 |
ORS | 输出的记录分割符 默认为换行符 |
FNR | 分别计数 |
FILENAME | 显示当前文件名 |
ARGC | 显示参数个数 |
ARGV | 打印数组参数 |
注:内置变量很多,参阅相关资料
自定义变量
- 自定义变量(区分字符大小写)
- -v var=value
- 在program中直接定义
- 示例
[root@localhost ~]# awk -v name=root '{print name}' /etc/passwd
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
root
- 变量调取还可以这样
[root@localhost ~]# awk '{sex="male";print sex }' /etc/passwd
male
male
male
male
male
male
male
male
male
male
male
male
male
male
male
- 还可以把他写成一个脚本如
[root@localhost ~]# vi f1.awk
{sex="male";print sex}
~
~
- 把他显示调取出来,但是要记住在里面不要放单引号不然出错
[root@localhost ~]# awk -f f1.awk /etc/passwd
male
male
male
male
male
male
male
male
male
male
male
printf
- 格式化输出:printf “FORMAT”, item1, item2, ...
- 必须指定FORMAT, 也就是格式
- 不会自动换行,需要显式给出换行控制符,\n
- FORMAT中需要分别为后面每个item指定格式符
- 格式符:与item一一对应
输出控制符 | 含义 |
---|---|
%C | 显示字符的ASCII码 |
%d,%i | 显示十进制整数 |
%e ,%E | 显示科学计数法数值 |
%f | 显示为浮点数 |
%g ,%G | 以科学计数法或浮点形式显示数值 |
%s | 显示字符串 |
%u | 无符号整数 |
%% | 显示%自身 |
- 修饰符:
-#[.#]:
第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f- -: 左对齐(默认右对齐) %-15s
- +:显示数值的正负符号 %+d
- 示例
[root@localhost ~]# awk -F: '{printf "%s---%d\n", $1,$3}' /etc/passwd
root---0
bin---1
daemon---2
adm---3
lp---4
sync---5
shutdown---6
halt---7
mail---8
operator---11
games---12
ftp---14
nobody---99
systemd-bus-proxy---999
systemd-network---192
dbus---81
- 如果你想右对齐可以这样,因为默认是右对齐
[root@localhost ~]# awk -F: '{printf "%s---%d\n", $1,$3}' /etc/passwd
root---0
bin---1
daemon---2
adm---3
lp---4
sync---5
shutdown---6
halt---7
mail---8
operator---11
games---12
ftp---14
nobody---99
systemd-bus-proxy---999
systemd-network---192
dbus---81
- 如果你想左对齐,可以这样
[root@localhost ~]# awk -F: '{printf "%-30s---%d\n", $1,$3}' /etc/passwd
root ---0
bin ---1
daemon ---2
adm ---3
lp ---4
sync ---5
shutdown ---6
halt ---7
mail ---8
operator ---11
games ---12
ftp ---14
nobody ---99
systemd-bus-proxy ---999
systemd-network ---192
- 还可以这样玩,反正自己看着玩
[root@localhost ~]# awk -F: '{printf "%+30s---%+30d\n", $1,$3}' /etc/passwd
root--- +0
bin--- +1
daemon--- +2
adm--- +3
lp--- +4
sync--- +5
shutdown--- +6
halt--- +7
mail--- +8
operator--- +11
games--- +12
- 还可以添加字符串,是里面不是外面注意
[root@localhost ~]# awk -F: '{printf "username:%-30s%-10d\n", $1,$3}' /etc/passwd
username:root 0
username:bin 1
username:daemon 2
username:adm 3
username:lp 4
username:sync 5
username:shutdown 6
username:halt 7
username:mail 8
username:operator 11
username:games 12
username:ftp 14
username:nobody 99
username:systemd-bus-proxy 999
username:systemd-network 192
username:dbus 81
操作符
- 算术操作符:
- x+y, x-y, x*y, x/y, x^y, x%y
- -x: 转换为负数
- +x: 转换为数值
- 字符串操作符:没有符号的操作符,字符串连接
- 赋值操作符:
- =, +=, -=, *=, /=, %=, ^=
- ++, --
- 比较操作符:
- ==, !=, >, >=, <, <=
- 模式匹配符:~:左边是否和右边匹配包含 !~:是否不匹配
- 示例
- 下面的意思是如果$0包含root就打印,没有就不打印
[root@localhost ~]# awk -F: '$0 ~ /root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
- 如下我想打印小于UID100的用户
[root@localhost ~]# awk -F: '$3<=1000{print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-bus-proxy 999
systemd-network 192
- 如果我想打印UID大于100的用户
[root@localhost ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534
mageedu 1000
- 逻辑操作符:与&&,或||,非!
- 示例
[root@localhost ~]# awk -F: '$3>=0 && $3<=1000 {print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-bus-proxy 999
systemd-network 192
dbus 81
- 或者小于10大于1000,的打印出来
[root@localhost ~]# awk -F: '$3<=0 || $3>=1000 {print $1,$3}' /etc/passwd
root 0
nfsnobody 65534
mageedu 1000
- 还可以取非
[root@localhost ~]# awk -F: ' ! ($3>1000) {print $1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-bus-proxy 999
systemd-network 192
dbus 81
正则表达式
正则表达式要多练这里只举几个例子
如果我只想用AWK来提取磁盘信息,怎么取,我们可以用包含来提取
[root@localhost ~]# df|awk '$0 ~ "^/dev/sd"'
/dev/sda2 41922560 388520 41534040 1% /
/dev/sda3 20961280 2679012 18282268 13% /usr
/dev/sda1 508580 148756 359824 30% /boot
- 当前里面还可以取反
[root@localhost ~]# df|awk '$0 !~ "^/dev/sd"'
Filesystem 1K-blocks Used Available Use% Mounted on
devtmpfs 2008832 0 2008832 0% /dev
tmpfs 2023456 0 2023456 0% /dev/shm
tmpfs 2023456 8800 2014656 1% /run
tmpfs 2023456 0 2023456 0% /sys/fs/cgroup
tmpfs 404692 0 404692 0% /run/user/0
BEGIN 和END 模块
- 通常,对于每个输入行,awk 都会执行每个脚本代码块一次。然而,在许多编程情况中
- 可能需要在awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况,awk 允许
- 您定义一个BEGIN 块。我们在前一个示例中使用了BEGIN 块。因为awk 在开始处理输入文件之前会执行BEGIN 块
- 因此它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它
在程序中以后会引用的全局变量的极佳位置
三目表达式
- 三目就是三个元素,三个组成部分,第一部分冒号,以此类推
- 示例
[root@localhost ~]# awk -F: '{$3>=1000?username="common user":username="sysuser";printf "%s %s %d\n" ,username,$1,$3}' /etc/passwd
sysuser root 0
sysuser bin 1
sysuser daemon 2
sysuser adm 3
sysuser lp 4
sysuser sync 5
sysuser shutdown 6
sysuser halt 7
sysuser mail 8
sysuser operator 11
sysuser games 12
sysuser ftp 14
sysuser nobody 99
- 或者来对齐下
[root@localhost ~]# awk -F: '{$3>=1000?username="common user":username="sysuser";printf "%s %20s %20d\n" ,username,$1,$3}' /etc/passwd
sysuser root 0
sysuser bin 1
sysuser daemon 2
sysuser adm 3
sysuser lp 4
sysuser sync 5
sysuser shutdown 6
sysuser halt 7
sysuser mail 8
sysuser operator 11
sysuser games 12
sysuser ftp 14
sysuser nobody 99
sysuser systemd-bus-proxy 999
sysuser systemd-network 192
sysuser dbus 81
sysuser polkitd 998
sysuser colord 997
sysuser abrt 173
sysuser libstoragemgmt 996
sysuser rpc 32