awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
1.命令行方式awk [-F field-separator] 'commands' input-file(s) 其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。 在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。2.shell脚本方式 将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。 相当于shell脚本首行的:#!/bin/sh可以换成:#!/bin/awk3.将所有的awk命令插入一个单独文件,然后调用:awk -f awk-script-file input-file(s) 其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。awk工作流程是这样的:读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是"空白键" 或 "[tab]键",所以$1表示登录用户,$3表示登录用户ip,以此类推。
如果只是显示/etc/passwd的账户和账户对应的shell,而账户与shell之间以逗号分割,而且在所有行添加列名name,shell,在最后一行添加"blue,/bin/nosh"。
cat /etc/passwd |awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "blue,/bin/nosh"}'name,shell root,/bin/bash daemon,/bin/shbin,/bin/shsys,/bin/sh.... blue,/bin/nosh
awk工作流程是这样的:先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录・・・・・・直到所有的记录都读完,最后执行END操作。
搜索/etc/passwd有root关键字的所有行
#awk -F: '/root/' /etc/passwdroot:x:0:0:root:/root:/bin/bash
这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。
搜索支持正则,例如找root开头的: awk -F: '/^root/' /etc/passwd
搜索/etc/passwd有root关键字的所有行,并显示对应的shell
# awk -F: '/root/{print $7}' /etc/passwd /bin/bash
这里指定了action{print $7}
awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。
ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk浏览的文件名 FNR 浏览文件的记录数 FS 设置输入域分隔符,等价于命令行 -F选项 NF 浏览记录的域的个数 NR 已读的记录数 OFS 输出域分隔符 ORS 输出记录分隔符 RS 控制记录分隔符
此外,$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。
统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
#awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwdfilename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/shfilename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/shfilename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh
使用printf替代print,可以让代码更加简洁,易读
awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
awk中同时提供了print和printf两种打印输出的函数。
其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。
printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。
变量和赋值
除了awk的内置变量,awk还可以自定义变量。
下面统计/etc/passwd的账户人数
/etc/::root:/root:/bin/
count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开。
这里没有初始化count,虽然默认是0,但是妥当的做法还是初始化为0:
awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd[start]user count is 0root:x:0:0:root:/root:/bin/bash ... [end]user count is 40
统计某个文件夹下的文件占用的字节数
-l |
如果以M为单位显示:
-l | [end]size is 8.25889 M
Awk的输出:
Print item1,item2
要点
如果 print后面没有数据就是显示$0
print item1, item2,...
要点:
(1) 各项目之间使用逗号分隔,而输出时则使用输出分隔符分隔;
(2) 输出的各item可以字符串或数值、当前记录的字段、变量或awk的表达式;数值会被隐式转换为字符串后输出;
(3) print后面item如果省略,相当于print $0;输出空白,使用pirnt""
-Fchar :输入分隔符
例如:
显示用户名
显示的是全部内容
Awk的内置变量在BEGIN中定义
A: FS: 输入时字段分隔符
例
RS :输出时的分隔符
OFS:输出时的字段分隔符
显示的内容会把:当做分隔符形成一个文件形式的显示出来
NF:每行的字段数 NR: 行数,所有文件一并统计
FNR:统计当前文件{个文件分别计数}
ARGV:数组,保存命令本身这个字符,awk '{print $0}' 1.txt 2.txt,意味着ARGV[0]保存awk,
ARGC: 保存awk命令中参数的个数;
FILENAME: awk正在处理的当前文件的名称
例子:
2.2 可自定义变量
-v var_name=VALUE
变量名区分字符大小写;
(1) 可以program中定义变量;
(2) 可以命令行中通过-v选项自定义变量;
3、awk的printf(打印格式)命令
命令的使用格式:printfformat, item1, item2,...
要点:
(1) 要指定format(格式);
(2) 不会自动换行;如需换行则需要给出\n
(3) format用于为后面的每个item指定其输出格式;
format格式的指示符都%开头,后跟一个字符:
%c: 显示字符的ASCII码;
%d, %i: 十进制整数;
%e, %E: 科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法格式或浮点数格式显示数值;
%s: 显示字符串;
%u: 显示无符号整数;
%%: 显示%自身;
在%与字母之间还可以加让你修饰符
修饰符:
#:显示宽度
-:左对齐
+:显示数值的符号
.#: 取值精度
当后面的数字不够时补零
4、awk输出重定向
print items > output-file
print items >> output-file
print items | command
特殊文件描述符:
/dev/stdin: 标准输入
/dev/stdout: 标准输出
/dev/stderr: 错误输出
5、awk的操作符
算术操作符:
x+y:相加
x-y:相减
x*y:相乘
x/y:x除以y
x**y, x^y:x的y次方
x%y:1去摸运算
-x:负值
+x:转换为数值
字符串操作符:连接
赋值操作符:
= ,+= ,-= ,*= ,/= ,%= ,^= ,++ ,--
如果模式自身是=号,要写为/=/
比较操作符:
<,<=,>,>=,==,!=
~:模式匹配,左边的字符串能够被右边的模式所匹配为真,否则为假;
!~:取相反的结果
逻辑操作符:
&&:与 ,||:或
我们来显示一个、etc/passwd下的gid>=500显示jin否者显示shuai
[root@handev]# awk-F: '{$3>=500?han="jin":han="shuai";print$3,"is",han}' /etc/passwd
、模式
(1) Regexp: 格式为/PATTERN/
仅处理被/PATTERN/匹配到的行;
(2) Expression: 表达式,其结果为非0或非空字符串时满足条件;
仅处理满足条件的行;
(3) Ranges: 行范围,此前地址定界,startline, endline
仅处理范围内的行
(4) BEGIN/END: 特殊模式,仅在awk命令的program运行之前(BEGIN)或运行之后(END)执行一次;
(5) Empty:空模式,匹配任意行;
、控制语句
8.1 if-else
格式:if (condition) {then body} else {else body}
例子:如果gid>=500 显示用户名后加上isa common user否者后面加上is an admin or system user
# awk -F: '{if ($3>=500) {print$1,"is a common user"} else {print $1, "is an admin or systemuser"}}' /etc/passwd
显示/etc/inittab下字段数大于等于8的哪一行
# awk'{if (NF>=8) {print}}' /etc/inittab
8.2 while
格式:while (condition) {while body}
例子:显示当i小于等于自己的字段数时就显示字符串(为单数的)行
# awk '{i=1; while(i<=NF){printf "%s ",$i;i+=2};print ""}' /etc/inittab
例子:当i小于等于自己的字段数且长度小于6时,做累加显示其行数
# awk '{i=1; while (i<=NF){if(length($i)>=6) {print $i}; i++}}' /etc/inittab
length()函数:取字符串的长度
8.3 do-while循环
格式:do {do-while body} while (condition)
8.4 for循环
格式:for (variable assignment; condition; iteration process) {for body}
# awk '{for(i=1;i<=NF;i+=2){printf "%s ",$i};print ""}'/etc/inittab
# awk '{for (i=1;i<=NF;i++){if(length($i)>=6) print $i}}' /etc/inittab