博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AWK 从不会到入门 Skr Skr
阅读量:6910 次
发布时间:2019-06-27

本文共 3873 字,大约阅读时间需要 12 分钟。

awk 含义: Aho, Weinberger & Kernighan interpreted language,是由这两个人共同发明的。

这不是一个工具,「这是一个伟大、有着奇怪的名字的语言」。

发音:awk [ɔk]

基本用法

awk '{ print }' /etc/passwd # 相当于 "cat /etc/passwd"awk '{ print $0 }' /etc/passwd # 与前面一行语句等价
  1. 花括号里的 print 函数用于将匹配到的每一行逐行打印出来
  2. print 和 print $0 等价

Multiple Fields

awk -F":" '{ print "username: " $1 "\t\tuid:" $3 }' /etc/passwd # 打印第一列和第三列的字符串,并以制表符分隔awk -F":" '                    \BEGIN{                         \    print "username\tuid"     \}; {                         \    print $1 "\t" $3         \}' /etc/passwd # 同上,但是将 username 和 uid 放置表头打印,看起来更美观
  1. -F 参数表示以 ":" 作为分隔符
  2. BEGIN 表示会在匹配第一行之前执行,因此很适合用作打印表头

Block(pattern-action,man-page 的说法)

如你所见,AWK 单引号内的脚本被称作「AWK Script」,脚本内由一个或多个花括号对组成,每一个花括号被叫做 Block。像「基本用法」里的单个 Block 是最简单的 Block。AWK 是按行处理文本的,每拿到一行字符串,都会将 AWK Script 内的 Block 按序匹配,匹配成功时则执行 Block 内的代码

awk '                         \BEGIN {                     \    FS = ":";                 \    count = 0;                \    print "username\tuid";     \}                             \{                            \    count += 1;                \    print $1 "\t" $3        \}                             \END {                        \    print "Totals:" count     \}' /etc/passwdawk -f block.awk /etc/passwd # 如果你嫌在命令行里输入麻烦,还可以将脚本以文件的方式执行

以上代码共有三个 Block,awk 每拿到一行字符串都会从前到后匹配这三个 Block,如若匹配上,则执行里面的代码。BEGIN 里定义了分隔符 FS(Field Seperator),这和之前的「Multiple Fields」里的 -F 选项是完全等价的效果。此外还定义了一个记录行数的变量 count,第二个 Block 没有定义任何条件,因此从第一行到最后一行都会被匹配成功!END 行最后输出行数。

awk 会在待匹配的文本第一行之前和最后一行之后各插入一行空行BEGINEND Block 则只有当分别匹配到这两行空行的时候才会执行。BEGIN 和 END 就好像语法糖一样,只是执行的时间一个最靠前,一个最靠后,其它与正常的 Block 并没有任何区别

正因为 BEGIN 这样的特性,因此你可以将变量定义、打印表头等初始化工作放在这里;END 适合用来做一些总结性的操作,打印行数、总字符数、行平均长度等等。

带条件的 Block

awk '                     \BEGIN { x=0 }             \/^$/  { x=x+1 }         \END   { print "I found " x " blank lines. :)" }'  file

以上代码用于打印文件中所有的空行,如果你是 JSer 或者 Perl-er,可能会对 /^$/ 比较熟悉,借鉴关系链:JavaScript <- Perl <- awk。awk 可以说是这套正则表示的鼻祖。

其实在每一个 Block 之前都存在一个隐含条件,无条件的 Block 会匹配所有文件中存在的行(不包括 awk 插入的两行空行)。当 Block 被附加条件后,只有当条件为真时才会执行。

awk '( $1 == /[0-9]+\.[0-9]*/ ) && NR%3 { print }' file

以上仅仅打印以浮点数开头且行数不为 3 的倍数的行,由于 AWK Script 是弱类型的,因此像 0 会被判为 false。在 awk 里,Record 就是行,因此 NR 表示 Number of Record。

在 AWK Script 中,所有变量的类型都是 string,当对 string 进行算术运算(比如加减乘除)时,awk 会将string 解析为 number,如果不是合法的 number,则视为 0;然后再进行算术运算。

为了更好的表现 BEGIN 的含义,欣赏下面的代码:

awk ' !/^$/ && NR <= 100 {          \    if (NR == 1) {                  \        FS = ":";                     \    }                               \    # 过滤掉注释和 NF 小于 3 的行      \    if (!($1 ~ /^#/) || NF >= 3) {  \           print $1 ":" $3;              \    }                               \}' /etc/passwd

整个代码只有一个 Block,这个 Block 只有在非空的行以及行数小于 100 里才能执行,当 awk 拿到第一行(NR == 1)时,定义了分隔符 FS(Field Seperate),这原本是在 BEGIN Block 中完成的(因为这个例子中的第一个 if 每次都会被执行,浪费性能)。第二个 if 过滤掉注释语句且 NF(Number of Field)大于 3 才执行,在 awk 中,NF 表示每一行被 FS 分隔后得到的 Field 的数量,相当于 NF = line.split(FS)。这个例子说明了 BEGIN 和 END 仅仅是语法糖,在本质上和普通的 Block 没有任何区别。像 NF 和 FS 这一类的是 awk 的自带变量,变量可以出现在 Block 的匹配条件里,同时也可以修改自带变量的值来改变 awk 的行为

函数

awk 靠 AWK Script 脚本工作,为了方便,awk 提供了一些内置函数,以及允许你定义函数的功能。下面是一个找出 /etc/passwd 文件中第三列最大的数所对应的行。

function find_max(n1, n2){    if (n1 > n2) {        return n1;    }    return n2;}BEGIN {    FS = ":";    max = -1;}{    if (NF < 3) {        next    }    # 第一行    max = $3;    mR = NR;    while (getline == 1) {        _max = find_max(max,$3);        if (max < _max) {            max = _max;            mR = NR;        }    }}END {    print "max is:" max;    print "NR is:" mR;}

然后执行 awk -f ./max.awk /etc/passwd

find_max 是自定义函数,调用的时候要带上圆括号,像 getline 和 next 则是内建函数,内建函数的调用不需要带圆括号。其中 next 用来跳过本次执行,主要用于处理文件开头的一些注释;getline 用来获取下一行,getline 会把下一行赋值给 $x(x 代表数字)。如果没有下一行就返回 0,while 循环结束。getline 改变了 awk 的行为,awk 从开始到结束只执行了一次 Block。

还有一些数学函数(如 sin、cos、sqrt)以及字符串处理函数(length、sprintf 格式化字符串)属于内建函数。

总结

awk 可玩性极强,借助 AWK Script,你可以用它模拟其它常见的文本处理工具(谁又会这么做呢?)

参考链接

  • man awk

转载地址:http://hqfcl.baihongyu.com/

你可能感兴趣的文章
期年之痒
查看>>
cpanm perl模块自动安装
查看>>
深入讲解BGP协议synchronous原理
查看>>
简要总结最近遇到的5个问题
查看>>
中国象棋程序的设计与实现(七)--心得体会和开发日志
查看>>
浅显理解 Python 闭包
查看>>
学习Oracle分析函数(Analytic Functions)
查看>>
openstack学习笔记二 网络设置基础
查看>>
RabbitMQ基础
查看>>
有了安全边界,人工智能才能有序发展
查看>>
Qt在mainwindow下代码添加控件不能显示的问题
查看>>
【cocos2dx】使用VS插件在VS2012/2013上编辑和调试Quick-Cocos2d-x的Lua代码
查看>>
Centos6.0之pptpd+mysql+freeradius实现***帐号统一认证管理
查看>>
Excel导出数据
查看>>
解释Windows7“上帝模式”的原理
查看>>
httpClient4.* 使用教程
查看>>
相对和绝对路径、cd命令、创建和删除目录mkdir/rmdir 、rm命令
查看>>
yum安装配置nagios
查看>>
linux下Bash局部变量及信号捕捉等概念解释
查看>>
HTML5 input placeholder 颜色修改示例css
查看>>