awk学习笔记

awk是一种模式扫描和处理工具,相对于grep的查找,sed的编辑,它在对数据进行分析生成报表时显得尤为强大。awk通过逐行遍历一个或多个 文件的方式,查找模式匹配到的行,而后以指定的分隔符(缺省为空格)进行切片,然后针对切片数据进行处理和分析。事实上,gawk有自己的语言,其本身就 相当于一个解释器,允许用户创建简短的程序读取输入文件,对输入数据执行排序、计算以及生成报表操作,甚至可以类似bash shell实现诸如循环、数组、条件判断、函数、变量等功能,进而完成更为复杂的数据分析处理任务。

Gawk

gawk(GNU awk)是UNIX awk的GNU版,为方便linux用户使用,通常将/bin/awk以符号链接方式链接到/bin/gawk,以迎合用户的使用习惯。(下文有提到gawk的地方均以awk代替)

awk的使用方式

1、命令行方式

awk [-F field-separator] ‘COMMAND’inputfiles

//其中COMMAND是awk的执行命令,用来处理数据,[-F field-separator]是可选选项,inputfiles是待处理文件。

//awk使用中,需要处理的文件,逐行使用分隔符分割成若干个字段,称之为域,分隔符默认是空格,可使用-F选项来指定分隔符

2、shell脚本模式

将所需执行的awk命令插入awk脚本文件,然后在首行设置命令解释器为#!/bin/awk,通过键入脚本名的方式调用。

3、所有awk命令写入到一个单独的文件,当处理同一类文件需求时,使用awk -f awk-script inputfiles调用之,其中awk-script指awk脚本。

awk的基本语法

awk [OPTION] 'program' FILE1 FILE2…

program:PATTERN{ACTION STATEMENT} //program由语句组成,各语句之间使用;隔开,整个program要用单引号引起来

OPTION:选项

-F:指定分割符

例,指定分隔符为“:”,打印出系统上各用户名和morenshell

# awk -F: '{print $1,$7}' /etc/passwd

-v:指定变量

例,通过-v选项指定变量a=hello awk 然后将其打印出来

# awk -v a="hello awk" '{print a}'

另外,也可以通过特殊模式BEGIN(模式下述)来指定变量,如上例,也可以这样写

# awk 'BEGIN{a="hello awk"}{print a}'

-f:指定脚本文件

awk变量

awk的变量,可分类为内置变量和自定义变量

1、内置变量

2、自定义变量

自定义变量有两种方式(上文基本语法中已有示例,此处不再赘述),但是,在脚本中仍然可以声明变量。

(1)、awk -v VARIABLE_NAME VARIABLE_VALUE 'program' inputfiles

(2)、awk 'BEGIN{VARIABLE_NAME VARIABLE_VALUE}ACTION STATEMENT}' inputfiles

3、变量使用示例

(1)、FS输入分隔符,默认为空格

例如,默认分隔符使用awk提取/etc/inittab中的“#”,如下图可以看到,如果以空格分割,第一个域即为#(忽略最后一行)

# awk '{print $1}' /etc/inittab //效果如下(最后一行请忽略)

以“:”为分隔符,提取系统中用户名以及用户默认

# awk -v FS=":" '{print $1,$7}' /etc/passwd

(2)、输出分隔符,默认为空格(如上图上例显示结果),接上例,以:为输出分隔符显示输出结果

# awk -v FS=":" -v OFS=":" '{print $1,$7}' /etc/passwd

(3)、NR和FNR

显示/etc/{inittab,passwd}所有内容以及行数

# awk '{print NR,$0}' /etc/{inittab,passwd}//看下图,行数不分开计数

# awk '{print FNR,$0}' /etc/{inittab,passwd}//看下图,使用FNR单独计数行数

# awk 'BEGIN{print "filename","alone_lines","unit_lines"}{print FILENAME,NR,FNR}' /etc/{passwd,inittab,group}//还可以这样写来分别显示总行号和单独行号,此处不再贴图

(4)、ARGC显示参数个数

# awk -F: '{print $1}END{print ARGC}' /etc/passwd //如下图,显示参数为二(经验证,貌似program也被识别成为一个参数,再加上后面的文件故为2个参数?)

awk的模式

1、Regular Expression 正则表达式

如其名,使用正则表达式匹配模式,在需要注意的是,在awk中使用正则表达式,匹配字符串要使用双斜线括起来,而后匹配到的行将被切片并分析处理,反之将略过。

取出/etc/passwd中包含root的行并打印出用户名和默认shell

# awk -F: ‘/root/ {print $1,$7}' /etc/passwd

2、Expression 表达式,当表达式的值为真(非零或非空)的行被匹配,仅处理匹配到的行

# awk -F: '$3>=500{print $1,$2,$3}' /etc/passwd

在此列出awk的常用操作符

如果模式自身是=,要写为/=/

条件表达式:

selector?if-true-express:if-false-express 只能是表达式不能使语句

条件表达式中,“:”两侧仅允许使用表达式而不能使用语句

# awk -F: '$3>=500?utype="common user":utype="admin or system user"{print $1 "is" utype} /etc/passwd

3、range行范围,有两种方式来定义此范围

(1)、pattern1,pattern2

从匹配到pattern1的行开始到匹配到pattern2的行为知,此范围的行被awk action处理

# awk 'NR==1,NR==10{print $1,$3,$7} /etc/passwd

4、特殊模式BEGIN和END

(1)、BEGIN在读取任何输入之前执行一次语句

# awk 'BEGIN{FS=":";OFS=":"}/root/{print $1,$3,$7} /etc/passwd

(2)、END在读取所有输入之后执行一次语句

# awk 'BEGIN{FS=":";OFS=":"}/root/{print $1,$3,$7}END{print "The end!"}' /etc/passwd

5、空模式

如果不指定模式则匹配文件中的所有行

awk重定向

1、输出重定向

awk可以使用shell的重定向符重定向输出,同样>代表覆盖式输出,>>代表追加。

覆盖式重定向

追加重定向效果

2、输入重定向

输入重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内 容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失 败,就返回-1,可以结合到while等流控制语句使用。

通过例子说明输入重定向用法

(1)、awk 'BEGIN{"date" | getline d; print d}'

getling函数读取date命令的输出结果并将其赋值给自定义变量d,然后打印变量d

(2)、awk 'BEGIN{"date" | getline d; split(d,mon); print mon[3]}'

getine函数读取date命令输出的结果并赋值给自定义变量d,split函数将变量d转化为数组mon,然后打印数组mon的第三个元素。

(3)、awk 'BEGIN{while("ls" | getline) print}'

getline函数读取ls命令的输出结果而后打印显示

awk之print和printf

1、print

用法:print item1,item2….

要点:

(1)、各item之间使用,号隔开,输出时默认以空格分隔

(2)、输出的item可以是字符串或数值、当前分隔出来的域(字段,如$1)、变量或awk的表达式,数值会隐式转换为字符串输出。

(3)、print后面的item项可以省略,此时相当于打印$0即整行内容;print ""表示打印空白行。

例:

# awk 'BEGIN{print "line1","line2","line3"}'

# awk -F: '{print $1,$3,$7}' /etc/passwd

2、printf

用来格式话打印输出内容

(1)、格式:

printf format,item1,ietm2,…

(2)、要点

printf需要指定format;

format用于指定后面每个item的格式;

printf不能自行换行,如需换行需给定\n;

使用修饰符可以使输出格式更加美观。

(3)、format的格式指示符,以%开始,后跟一个字符

%c:显示字符的ASCII吗

%d,%i:十进制整数

%e,%E:科学计数法显示数值

%f:显示浮点数本身

%g,%G:以科学计数法格式或浮点数显示数值

%s:显示字符串

%u:显示无符号整数

%%:显示%自身

修饰符

#:字段的显示宽度

.#:取值精度

-:左对齐

=+:显示数值的符号

(4)、例:

取出系统用户的用户名和默认shell,要求用户名左对齐,占用15个字符,字符串显示;要求默认shell左对齐,占用20字符,字符串显示

awk -F: ‘{printf "%-15s %-20s\n",$1,$7}' /etcpasswd

使用显示浮点数自身(%f)的方式显示,会自动补全精度,长于精度部分将会执行四舍五入

# awk 'BEGIN{printf "%f\n",3.15}'

当使用数字来定义字段占用字符长度时,要放在其它修饰符前面;小数点后面的数字代表精度

# awk 'BEGIN{printf "%-15.2\n",3.15}'

awk之action

1、常见action

(1)、表达式 Expression

(2)、控制语句 Control statements

(3)、组合语句 Commpound statments

(4)、输入语句 Input statments

(5)、输出语句 Output statements

2、awk常见控制语句以及使用示例

(1)、if-else语句 格式:if (condition) {then body} else {else body}

# awk -F: '{if($3>=500{print $1 "is a common user"} else {print $1 "is admin or systemuser"}' /etc/passwd

uid号大于等于500的显示为普通用户,小于500的显示为管理员或系统用户。

# awk -F: '{if(NF>=8){print}}' /etc/inittab

打印显示以冒号切割形成字段大于等于8的行

(2)、while语句 格式: 格式:while (condition) {while body}

awk '{i=1;while(i<=NF){printf "%s ",$i;i+=2}; print ""}' /etc/inittab

打印输出/etc/inittab中的奇数字段

打印出字符大于等于6的字段

# awk '{i=1;while(i<=NF{if(length($i<=6){print $i};i++}}' /etc/inittab

(3)、do-while循环 格式:格式:do {do-while body} while (condition)

# awk 'BEGIN{sum=0;i=0;do{sum+=i;i+=}while{i<=100};print sum;}'

求和1-100

(4)、for循环 格式:for (variable assignment; condition; iteration process) {for body}

# awk '{for(i=1,i<=NF,i+=2){printf "%s ",$1};print ""}' /etc/inittab

打印出/etc/inittab中的每行的奇数字段

for循环还可以用来遍历数组 格式:for (i in array) {for body}

# awk 'BEGIN{"date" | getline d; split(d,test);for (i in test) print test[i]}'

break 用于在满足条件的情况下跳出循环;continue用于在满足条件时忽略后面的语句,直接返回循环的顶端

(5)、next提前结束本行处理,进入下一行处理

取uid为奇数的用户和uid

# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd

(6)、数组

关联数组

array[index-expression]index-expression:可以使用任意字符串;如果某数组元素事先不存在,那么在引用时,awk会自动创建次元素并将其初始化为空串;因此,要判断某数组是否存在某元素,必须使用“index in array”这种格式A[first]="hello awk"print A[second]要遍历数组中的每一个元素,需要使用如下特殊结构:for (var in array) {for body}期中var会遍历array的索引,而非元素的值

(7)、awk的内置函数 split(string,array[,fieldsep[,seps]])能够将string标示的字符串以fieldsep为分隔符进行切片,并切片后的结果保存至array为名的数组中;数组下表从1开始

# awk 'BEGIN{split("root:x:0:0",user,":");for (i in user) print user[i]}'

由于本人水平有限,awk的使用先总结到这里吧,在以后的使用中再深入研究。

原文发布于微信公众号 - 马哥Linux运维(magedu-Linux)

原文发表时间:2015-10-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Spark学习技巧

Flink DataSet编程指南-demo演示及注意事项

Flink中的DataStream程序是对数据流进行转换的常规程序(例如,过滤,更新状态,定义窗口,聚合)。数据流的最初的源可以从各种来源(例如,消息队列,套接...

4.5K120
来自专栏数据结构与算法

cf444E. DZY Loves Planting(并查集)

然后cf正解居然是网络流??出给NOIP模拟赛T1???¥%……&((……%&((

13830
来自专栏对角另一面

lodash源码分析之数组的差集

本文为读 lodash 源码的第十七篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash

13940
来自专栏维C果糖

史上最简单的 MySQL 教程(九)「列类型 之 数值型」

所谓的列类型,其实就是指数据类型,即对数据进行统一的分类,从系统的角度出发是为了能够使用统一的方式进行管理,更好的利用有限的空间。

44080
来自专栏北京马哥教育

十分钟完成Bash 脚本进阶!列举Bash经典用法及其案例

前言:在linux中,Bash脚本是很基础的知识,大家可能一听脚本感觉很高大上,像小编当初刚开始学一样,感觉会写脚本的都是大神。虽然复杂的脚本是很烧脑,但是,当...

16130
来自专栏开发与安全

从零开始学C++之STL(一):STL六大组件简介

一、STL简介 (一)、泛型程序设计 泛型编程(generic programming) 将程序写得尽可能通用 将算法从数据结构中抽象出来,成为通用的 C...

23800
来自专栏企鹅号快讯

Python模块知识4:序列化Json/pickle

序列化与反序列化 序列化:把Python的基本数据类型转为字符串 反序列化:把字符串转为Python的基本数据类型 Python中用于序列化的两个模块: jso...

23090
来自专栏Taylor技术日志

关于char/varchar(n)中n的探究:字符数or字节数

很多时候我们不确定某个字段的长度,会使用varchar类型,比如某个字段定义为varchar(100),那这100的长度能存多少个中文?

45770
来自专栏鸿的学习笔记

Python写的Python解释器(七)--完结篇

在程序运行时,只会创建一次VirtualMachine实例,这是因为只有一个Python解释器。 VirtualMachine存储着call stack,异常状...

10830
来自专栏偏前端工程师的驿站

(cljs/run-at (JSVM. :all) "细说函数")

12110

扫码关注云+社区

领取腾讯云代金券