awk介绍
- awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出
- 有多种版本:New awk(nawk),GNU awk( gawk)
- gawk:模式扫描和处理语言
- 基本用法:
awk [options] ‘program’ var=value file…
awk [options] -f programfile var=value file…
awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{ action;… }’ file …
awk 程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块 、END语句块,共3部分组成
program通常是被单引号或双引号中
- 选项:
-F 指明输入时用到的字段分隔符
-v var=value: 自定义变量
awk不能修改文件,只做输出显示处理
[root@localhost ~]# which awk
/usr/bin/awk
[root@localhost ~]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 Dec 14 21:53 /usr/bin/awk -> gawk
awk语言
- 基本格式:awk [options] ‘program’ file…
- program:pattern{action statements;..}
- pattern和action:
pattern部分决定动作语句何时触发及触发事件
BEGIN,END
pattern决定了是针对那种类型的行进行处理。虽然默认把每一行都读进来,但是读进来的行要不要处理,可以定义pattern进行过滤,例如:如果满足pattern就执行动作,不满足就不符合条件,就可以直接跳到下一行开始。
action statements对数据进行处理,放在{}内指明。打印显示必要的内容
print, printf
print:简单的把必要的内容数据显示出来
printf:更加具体详细的定义显示的格式,例如添加控制符,打印的时候字段和字段之间有多宽、小数点有多少位
- 分割符、域和记录
awk执行时,由分隔符分隔的字段(域)标记,分割成若干个列,每个列系统会自动分配变量$1,$2..$n对应的表示他们,用$1,$2..$n分别表示这一行的第几列,称为域标识。$0为所有域,注意:和shell中变量$符含义不同
文件的每一行称为记录(默认回车换行分割记录)
省略action,则默认执行 print $0 的操作,打印一整行
$0为所有域,整行的所有字段
在bash中$0 表示程序本身
printf也是一个内部命令,作用和echo相似,按照一定格式显示字符串
[root@localhost ~]# type printf
printf is a shell builtin
[root@localhost ~]# man printf
NAME
printf – format and print data 格式化和打印数据
记录不一定非得是一行才成为一条记录,例如:别的形式
[root@localhost ~]# vim file
a:bb;ccc:ddd;
例如该文件中,可以认为“:”分开的为字段,“;”分开的为记录(一行),不是按照回车换行为记录的分隔符,默认记录的分割符是回车换行,也可以是别的字符
awk工作原理
- 第一步:执行BEGIN{action;… }语句块中的语句
- 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
从命令的执行结果来的数据去读取第一行,然后去执行pattern中的action,看是否符合pattern定义,如果符合pattern定义就执行里面的action,不符合就不处理,读取下一行,知道文件处理完
- 第三步:当读至输入流末尾时,执行END{action;…}语句块
- BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个 可选的语句块,比如变量初始化、打印输出表格的表头等语句通常 可以写在BEGIN语句块中
- END语句块在awk从输入流中读取完所有的行之后即被执行,比如 打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
- pattern语句块中的通用命令是最重要的部分,也是可选的。如果 没有提供pattern语句块,则默认执行{ print },即打印每一个读取 到的行,awk读取的每一行都会执行该语句块
awk
- print格式: print item1, item2, … item1表示要打印的字符,可以是普通字符串,也可以是要打印的列
- 要点:
(1) 逗号分隔符
(2) 输出的各item可以字符串,也可以是数值;当前记录的字段、 变量或awk的表达式
(3) 如省略item,相当于print $0
- 示例:
awk ‘{print “hello,awk”}’
awk –F: ‘{print}’ /etc/passwd
awk –F: ‘{print “wang”}’ /etc/passwd
awk –F: ‘{print $1}’ /etc/passwd awk –F: ‘{print $0}’ /etc/passwd
awk –F: ‘{print $1”\t”$3}’ /etc/passwd tail –3 /etc/fstab |awk ‘{print $2,$4}’
例子:
如果pattern忽略不写,就会处理所有行
每读一行显示一行,读进来一看,pattern未定义,符合条件,符合条件就打印
[root@localhost /app]# awk ‘{print “hello”}’ /etc/issue
hello
hello
从标准输入读取输入进行打印
[root@localhost /app]# awk ‘{print “hello”}’
a
hello
b
hello
awk可以读取标准输入
[root@localhost /app]# cat /etc/issue | awk ‘{print “hello”}’
hello
hello
hello
管道把前一个命令的标准输出作为后一个命令的标准输入
[root@localhost /app]# awk ‘{print “hello\nclass27″}’ /etc/centos-release
hello
class27
做数字运算,只要是字符串,就需要加引号引起来,数字不需要加引号
[root@localhost /app]# awk ‘{print 2*3}’ /etc/centos-release
6
[root@localhost /app]# awk ‘{print 2^3}’ /etc/centos-release
8
[root@localhost /app]# awk ‘{print 2/3}’ /etc/centos-release
0.666667
希望取出特定的字段,awk默认的分隔符是空格
[root@localhost /app]# awk -F “:” ‘{print $1,$3,$7}’ passwd
取分区的利用率
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $5}’
8%
1%
4%
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1,$5}’
/dev/sda2 8%
/dev/sda3 1%
/dev/sda1 4%
{print $1,$5},$1 和 $5 之间使用“,”,输出时字段的分割符为空格,也可以进行指定,例如:
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1″——“$5}’
/dev/sda2——8%
/dev/sda3——1%
/dev/sda1——4%
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1”\t“$5}’
/dev/sda2 8%
/dev/sda3 1%
/dev/sda1 4%
[root@localhost /app]# df | grep /dev/sd | awk ‘{print $1”\n“$5}’
/dev/sda2
8%
/dev/sda3
1%
/dev/sda1
4%
$0打印整行内容
默认不写也是打印整行内容
[root@localhost ~]# df | grep ‘dev/sd’ | awk ‘{ print }’
/dev/sda2 52403200 16332416 36070784 32% /
/dev/sda5 20961280 51048 20910232 1% /app
/dev/sda1 1038336 227464 810872 22% /boot
[root@localhost ~]# df | grep ‘dev/sd’ | awk ‘{ print $0 }’
/dev/sda2 52403200 16332416 36070784 32% /
/dev/sda5 20961280 51048 20910232 1% /app
/dev/sda1 1038336 227464 810872 22% /boot
awk变量
- 变量:内置和自定义变量
- FS:输入字段分隔符,默认为空白字符
awk -v FS=’:’ ‘{print $1,FS,$3}’ /etc/passwd
awk –F: ‘{print $1,$3,$7}’ /etc/passwd
awk -v FS=’:’ 等价于 awk -F ‘:’
FS:field,称为域、字段、列column、属性
行,称为记录,record
- OFS:输出字段分隔符,默认为空白字符
awk -v FS=‘:’ -v OFS=‘:’ ‘{print $1,$3,$7}’ /etc/passwd
- RS:输入记录分隔符,指定输入时的换行符
awk -v RS=’ ‘ ‘{print }’ /etc/passwd
- ORS:输出记录分隔符,输出时用指定符号代替换行符
awk -v RS=’ ‘ -v ORS=’###’‘{print }’ /etc/passwd
- NF:字段数量
awk -F: ‘{print NF}’ /etc/fstab,引用内置变量不用$
awk -F: ‘{print $(NF-1)}’ /etc/passwd
- NR:记录号
awk ‘{print NR}’ /etc/fstab ; awk END'{print NR}’ /etc/fstab
-v表示给变量赋值,FS是awk自带的变量,字段的分隔符,指定文件输入的分隔符是什么
[root@localhost /app]# awk -F ‘:’ ‘{print $1,$3}’ passwd
[root@localhost /app]# awk -v FS=’:’ ‘{print $1,$3}’ passwd
变量的好处是可以在awk中输出时使用
[root@localhost /app]# awk -v FS=’:’ ‘{print $1,FS,$3}’ passwd
root : 0
bin : 1
awk还可以使用bash变量,例如调用bash中的变量
[root@localhost /app]# sep=”:”;awk -v FS=”$sep” ‘{print $1,FS,$3}’ passwd
root : 0
bin : 1
-F只能在外面使用bash中的变量,但是里面就无法使用了
[root@localhost ~]# sep=”:”;awk -F “$sep” ‘{print $1,”:”$3}’ passwd
root :0
bin :1
输出分隔符
[root@localhost /app]# awk -v FS=’:’ -v OFS=’+’ ‘{print $1,$3}’ passwd
root+0
bin+1
输入分割符决定字段之间怎么分割进行处理
输出分隔符决定字段之间怎么输出进行显示
把一个文件读进来怎么知道怎样算是一条记录?默认回车换行是一条记录
例如:认为一条记录的分割符为‘;’,字段的分隔符默认为空白符
[root@localhost /app]# cat file
aa bb cc;ee
ff oo;xx
yy zz
[root@localhost /app]# awk -v RS=”;” ‘{print $2}’ file
bb
ff
yy
[root@localhost /app]# cat file
a
b
c aa
bb
cc aaa
bb
ccc aaa
以空格作为行的分隔符
[root@localhost /app]# awk -v RS=” ” ‘{ print $1,$2}’ file
a b
aa bb
aaa bb
aaa
以空格作为行的分隔符,所以abc算是一条记录,默认字段的分割符为空白符,回车换行也是空白符,所以a是$1,b是$2,c是$3,所以第一行为a b
所以,记录分别是:
a b c
aa bb cc
aaa bb ccc
aaa
输出的时候一条一条的记录默认是换行分割出来的,输出的时候,记录和记录之间到的默认分割符是回车换行
指定输出的分隔符
[root@localhost ~]# cat f2.txt
a b
aa bb
aaa bb
aaa
指定输出记录的分隔符
[root@localhost ~]# awk -v RS=” ” -v ORS=”—“ ‘{print $1,$2}’ f2.txt
a —b aa—bb aaa—bb aaa—
字段数量NF
显示每个行有多少个字段
[root@localhost ~]# awk -F: ‘{print NF}’ /etc/passwd
7
输出最后一个字段
[root@localhost ~]# awk -F: ‘{print $NF}’ /etc/passwd
/bin/bash
输出倒数第二个字段
[root@localhost ~]# awk -F: ‘{print $(NF-1)}’ /etc/passwd
/root
取出远程连接IP
[root@localhost ~]# ss -nt | awk ‘{print $NF}’ | awk -F: ‘{print $1}’
Address
172.18.101.66
取出分区利用率
[root@localhost ~]# df | grep ‘/dev/sd’ | awk ‘{print $(NF-1)}’|awk -F% ‘{print $1}’
32
1
22
取http访问日志
[root@localhost /app]# awk ‘{print $1}’ /var/log/httpd/access_log
172.18.101.66
NR:记录号,每条记录的编号
[root@localhost /app]# awk ‘{print NR,$0}’ /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
空行也算行号
[root@localhost /app]# awk ‘{print NR,$0}’ /etc/fstab
1
2 #
3 # /etc/fstab
同时处理多个文件
[root@localhost /app]# awk ‘{print NR,$0}’ /etc/fstab /etc/issue
在第一个文件输出完之后接着输出第二个文件的内容
同时处理多个文件,每个文件独立编号
[root@localhost /app]# awk ‘{print FNR,$0}’ /etc/fstab /etc/issue
1
2 #
3 # /etc/fstab
1 \S
2 Kernel \r on an \m
3
显示文件名
[root@localhost /app]# awk ‘{print FNR,FILENAME,$0}’ /etc/fstab /etc/issue
1 /etc/fstab
2 /etc/fstab #
3 /etc/fstab # /etc/fstab
1 /etc/issue \S
2 /etc/issue Kernel \r on an \m
3 /etc/issue
awk
- FNR:各文件分别计数,记录号
awk ‘{print FNR}’ /etc/fstab /etc/inittab
- FILENAME:当前文件名
awk ‘{print FILENAME}’ /etc/fstab
- ARGC:命令行参数的个数
awk ‘{print ARGC}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab
- ARGV:数组,保存的是命令行所给定的各参数
awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab
awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab
命令行参数的个数
[root@localhost ~]# awk ‘{print ARGC}’ /etc/fstab /etc/issue
3
[root@localhost /app]# awk ‘{print ARGV[0]}’ /etc/fstab /etc/issue
awk
[root@localhost /app]# awk ‘{print ARGV[1]}’ /etc/fstab /etc/issue
/etc/fstab
[root@localhost /app]# awk ‘{print ARGV[2]}’ /etc/fstab /etc/issue
/etc/issue
三个参数从0开始编,认为awk也是参数之一
awk变量
- 自定义变量(区分字符大小写)
(1) -v var=value
(2) 在program中直接定义
- 示例:
awk -v test=’hello gawk’ ‘{print test}’ /etc/fstab
awk -v test=’hello gawk’ ‘BEGIN{print test}’
awk ‘BEGIN{test=”hello,gawk”;print test}’
awk –F:‘{sex=“male”;print $1,sex,age;age=18}’ /etc/passwd
cat awkscript {print script,$1,$2} awk -F: -f awkscript script=“awk” /etc/passwd
自定义变量
# awk -v sep=”:” -F: ‘{print $1sep$3}’ /etc/passwd
root:0
分别进行定义
# awk -v uid=”uid” -F: ‘{user=”username”;print user”:”$1,uid”:”$3}’ /etc/passwd
username:root uid:0
# awk -v user=”username” -v uid=”uid” -F: ‘{print user”:”$1,uid”:”$3}’ /etc/passwd
username:root uid:0
在program中直接定义
# awk -F: ‘{user=”username”;uid=”uid”; print user”:”$1,uid”:”$3}’ /etc/passwd
username:root uid:0
定义在awk程序里面不能使用bash中的变量,在外部定义可以使用bash中的变量
# u=”user”; awk -F: -v user=”$u” ‘{uid=”uid”; print user”:”$1,uid”:”$3}’ /etc/passwd
user:root uid:0
先使用后定义会现第一行不生效的问题
# awk -F: ‘{print user”:”$1,uid”:”$3;user=”user”;uid=”userid”}’ /etc/passwd
:root :0
user:bin userid:1
原因:第一行读取进来进行处理的时候,user和uid还是未定义的状态,但是到第二行的时候,就已经是定义了的状态了。这一行定义的变量将会在下一行起作用。为避免出现问题,建议先声明后使用
把awk的指定放入文件中去
[root@localhost ~]# cat awk.script
{user=”username”;uid=”userid”;print user”:”$1,uid”:”$3}
[root@localhost ~]# awk -F: -f awk.script /etc/passwd
username:root userid:0
本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/90685