awk 从入门到精通

时间:2022-10-29 16:05:00

1、简介
主要用来处理文本数据,处理效率高(于shell),代码简洁高效,绝对不会遇到内存溢出

2、命令处理模式:
按行处理,一行一行执行(和shell一样)
3、命令格式:

awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
-F指定分隔符 -f调用脚本 -v定义变量 var=value
' ' 引用代码块(''单引号)
BEGIN 初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
// 匹配代码块,可以是字符串或正则表达式
{} 命令代码块,包含一条或多条命令
; 多条命令使用分号分隔
END 结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息

4、awk正则:

$0           当前所在行
$n 每行第n个字段(打印列) n可以换成任一正整数
NF 字段数量变量
NR 每行的记录号,多文件记录递增
FNR 与NR类似,不过多文件记录不递增,每个文件都从1开始
\t 制表符
\n 换行符
FS BEGIN时定义分隔符
RS 输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
~ 匹配,与==相比不是精确比较
!~ 不匹配,不精确比较
== 等于,必须全部相等,精确比较
!= 不等于,精确比较
&&  逻辑与
|| 逻辑或
+ 匹配时表示1个或1个以上
/[0-9][0-9]+/ 两个或两个以上数字
/[0-9][0-9]*/ 一个或一个以上数字
FILENAME 文件名
OFS 输出字段分隔符, 默认也是空格,可以改为制表符等
ORS 输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
-F'[:#/]' 定义三个分隔符
-F":#/"

5、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/awk

3.将所有的awk命令插入一个单独文件,然后调用:

awk -f awk-script-file input-file(s)

其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

6、操作
最近登录账户的查看:(-F指定分隔符仅支持:不加”“,其它分隔符不加”“全部不识别)

last -n 2 | awk  '{print $1}'      //print打印指定内容

awk '{print}' /etc/passwd 等于 awk '{print $0}' /etc/passwd 等于 cat /etc/passwd

awk '{print " "}' /etc/passwd //不输出passwd的内容,而是输出相同个数的空行,进一步解释了awk是一行一行处理文本

awk '{print "a"}' /etc/passwd //输出相同个数的a行,一行只有一个a字母
awk -F":" '{print $1}' /etc/passwd
awk -F: '{print $1}' /etc/passwd
awk -F'[:]' '{print $1}' /etc/passwd


awk -F"/" '{print $2}' /etc/passwd
awk -F: '{print $1; print $2}' /etc/passwd(换行显示) 等于 awk -F: '{print $1, $2}'(不换行) /etc/passwd//将每一行的前二个字段,分行输出,进一步理解一行一行处理文本
awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd //指定以tab键分隔第1,3,6个字段 OFS指定分隔符

7、变量:-v
(1)内置变量

ARGC               命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符-F
ORS 输出记录分隔符
RS 控制记录分隔符

统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:

#awk -F '/' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:29,columns:6,linecontent:saslauth:x:498:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
filename:/etc/passwd,linenumber:30,columns:6,linecontent:postfix:x:89:89::/var/spool/postfix:/sbin/nologin
filename:/etc/passwd,linenumber:31,columns:6,linecontent:pulse:x:497:496:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
filename:/etc/passwd,linenumber:32,columns:6,linecontent:sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
filename:/etc/passwd,linenumber:33,columns:4,linecontent:tcpdump:x:72:72::/:/sbin/nologin

打印:文件名,行数,字段数,当前行内容:

awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
awk -F ':' '{printf("filename:%s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
awk -F ':' '{printf "filename:"FILENAME",linenumber:"NR",columns:"NF",linecontent:"$0"\n"}' /etc/passwd

%10s:
输入时,%10s表示最多接受10个字符,多余的忽略;
输出时,%10s表示字符串长度不足10个时,左边补空格,保证占10个字节位置,10个及以上原样输出.

print和printf:
awk中同时提供了print和printf两种打印输出的函数。
print函数的参数:变量、数值或者字符串。(字符串必须用”“引用,参数用,分隔。如果没有, ,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。)
printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。
(2)自定义变量:
统计虚拟机/etc/passwd用户数量:

awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd

8、awk实现wordcount(词频统计)案例

vi a.log
my name is hahah .
14 years old
运行方式一:
vi wc.awk

{
for (i = 1; i<=NF; i++)
freq[$i]++
}
END{
for (word in freq)
printf "%s%d\n",word,freq[word]
}
运行:
awk -f wc.awk a.log
运行方式二:
vi wordcount_awk.sh
#!/bin/sh
awk -F " " '{
for (i = 1; i<=NF; i++)
freq[$i]++
}
END{
for (word in freq)
printf "%s%d\n",word,freq[word]
}'
$1

执行:
chmod u+x wordcount_awk.sh
./wordcount_awk.sh f.txt

9、打印九九乘法表

seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'