AWK简介

Awk是一种非常通用的编程语言,用于处理文件。我们将只教您足够的理解这一页中的例子,再加上一个smidgen。

为什么学习AWK ?

和grep、sed一样,AWK是UNIX shell编程的另一个基础。
AWK有三种变体:

  1. AWK - the (very old) original from AT&T
  2. NAWK - A newer, improved version from AT&T
  3. GAWK - The Free Software foundation's version

最初,我不打算讨论NAWK,但是一些UNIX供应商已经用NAWK替换了AWK,而且两者之间存在一些不兼容之处。如果我不警告你们这些不同之处,那就太残忍了。所以当我讲到这些的时候,我会强调一下。重要的是要知道,所有AWK的功能都在NAWK和GAWK中。NAWK的大部分功能(如果不是全部的话)都在GAWK中。NAWK是Solaris的一部分。GAWK 则不是。然而,Internet上的许多站点都有免费的资源。如果你使用Linux,你有了GAWK。但一般来说,假设我说的是经典的AWK,除非另有说明。

为什么AWK如此重要?它是一个优秀的过滤器和报告编写器。许多UNIX程序生成行和列信息。AWK是处理这些行和列的优秀工具,并且比大多数传统编程语言更容易使用AWK。它可以被认为是一个伪C解释器,因为它理解与C相同的算术运算符。AWK还具有字符串操作函数,因此它可以搜索特定的字符串并修改输出。AWK也有关联数组,这是非常有用的,也是大多数计算语言所缺乏的特性。关联数组可以使复杂的问题变得简单。

我将试着介绍基本的部分或AWK,并提到扩展/变体。“new AWK”或“nawk”出现在太阳系统上,您可能会发现它在许多方面都优于旧AWK。特别是,它有更好的诊断,并且不会打印出原始AWK容易输出的臭名昭著的“在行附近进行救援”消息。相反,“nawk”打印出它不理解的行,并用箭头突出显示不好的部分。GAWK 也会如此,这真的很有帮助。如果你发现自己需要一个功能,在AWK是非常困难的或不可能的,我建议你使用NAWK,GAWK,或者使用“a2p”转换程序把你的AWK脚本转换成PERL。PERL是一种了不起的语言,我一直在使用它,但是我不打算在这些教程中介绍PERL。我已经表明了我的意图,我可以问心无愧地继续下去。

许多UNIX实用程序都有奇怪的名称。AWK就是其中之一。它不是awkward的缩写。事实上,它是一种优雅而简单的语言。作品“AWK”来源于该语言的三个开发者的首字母:A. Aho, B. W. Kernighan和P. Weinberger。

基本结构

AWK程序的基本组织形式如下:

pattern { action }

模式(pattern)指定何时执行操作。与大多数UNIX实用程序一样,AWK是面向行的。也就是说,模式指定了一个测试,该测试以每一行读取为输入来执行。如果条件为真,则采取操作。默认模式匹配每一行。这是空白或null模式。另外两个重要的模式由关键字“BEGIN”和“END”指定。如您所料,这两个词指定了在读取任何行之前和读取最后一行之后要执行的操作。AWK程序如下:

BEGIN { print "START" }
      { print         }
END   { print "STOP"  }

在输入文件之前和之后分别添加一行。这不是很有用,但通过一个简单的改变,我们可以把它变成一个典型的AWK程序:

BEGIN { print "File\tOwner"}
{ print $8, "\t", $3}
END { print " - DONE -" }

在下一节中,我将改进这个脚本,但是我们将它称为“FileOwner”。但我们先不把它放到脚本或文件中。我将稍微介绍一下这部分。等一下,跟着我,这样你就能尝到AWK的味道了。

字符“\t”表示制表符,因此输出在偶数边界上对齐。“8”和“3”的含义类似于shell脚本。不是第8和第3个参数,而是输入行的第8和第3个字段。您可以将字段视为一列,您指定的操作对每一行列进行操作。

AWK和处理双引号内字符的shell之间有两个不同之处。AWK可以理解像“t”这样跟在“\”字符后面的特殊字符。Bourne和C UNIX shell则不理解。另外,与shell(和PERL)不同,AWK不计算字符串中的变量。为了解释,第二行不能这样写:

{print "$8\t$3" }

该示例将打印“83”。在引号内,$符号不是一个特殊字符。在外部,它对应一个字段。我说的第三和第八个字段是什么意思?考虑Solaris“/usr/bin/ls -l”命令,它有8列信息。System V版本(类似于Linux版本),“/usr/5bin/ls -l”有9列。第三列是所有者,第八列(或第九列)是文件名称。这个AWK程序可以用来处理“ls -l”命令的输出,打印出每个文件的文件名,然后是所有者。我来教你怎么做。

更新:在linux系统上,将“8”更改为“9”。

关于使用符号还有一点。在Perl等脚本语言和各种shell中,符号表示接下来的单词是变量的名称。Awk是不同的。符号表示我们正在引用当前行中的字段或列。在Perl和AWK之间切换时,必须记住“”有不同的含义。因此,下面的代码将打印两个“字段”以进行标准输出。打印的第一个字段是数字“5”,第二个字段是输入行上的第五个字段(或列)。

BEGIN { x=5 }
{ print x, $x}

执行AWK脚本

让我们开始编写第一个AWK脚本。有几种方法可以做到这一点。

假设第一个脚本名为“FileOwner”,那么调用将是

ls -l | FileOwner

如果当前目录中只有两个文件,则可能生成以下内容:

File    Owner

a.file  barnett
another.file barnett
- DONE -

这个脚本有两个问题。这两个问题都很容易解决,但是我将在介绍基本知识之前暂时不讨论这个问题。

脚本本身可以用多种方式编写。我已经展示了C shell (csh/tcsh)和Bourne/Bash/POSIX shell脚本。C shell版本应该是这样的:

#!/bin/csh -f
# Linux users have to change $8 to $9
awk '\
BEGIN   { print "File\tOwner" } \
        { print $8, "\t", $3}   \
END     { print " - DONE -" } \
'

当然,一旦您创建了这个脚本,您需要使这个脚本可执行:

chmod +x awk_example.1.csh

test:

ls -l | sh FileOwner

正如您在上面的脚本中看到的,如果不是脚本的最后一行,AWK脚本的每一行都必须有一个反斜杠。这是必要的,因为默认情况下,C shell不允许字符串超过一行。我有一长串关于使用C shell的抱怨。

Bourne shell(和大多数shell一样)允许引用字符串跨越几行:

!/bin/sh
# Linux users have to change $8 to $9 
awk '
BEGIN { print "File\tOwner" } 
{ print $8, "\t", $3}   
END { print " - DONE -" } 

再次说明,一旦它被创建,它必须是可执行的:

chmod +x awk_example1.sh

顺便说一下,我在教程中给出了示例脚本,并在文件名上使用扩展名来指示脚本的类型。当然,您可以通过输入以下代码把脚本“install”到您的home“bin”目录中:

cp awk_example1.sh $HOME/bin/awk_example1
chmod +x $HOME/bin/awk_example1

第三种类型的AWK脚本是“原生的”AWK脚本,其中不使用shell。您可以在文件中编写命令并执行:

awk -f filename

因为AWK也是一个解释器,就像shell一样,你可以节省一个步骤,在文件的开头添加一行代码,使文件可执行:

#!/bin/awk -f
BEGIN { print "File\tOwner" }
{ print $8, "\t", $3}
END { print " - DONE -" }

然后执行“chmod +x”并将此文件作为一个新的UNIX命令进行ise。

注意“#!/bin/awk”后面的“-f”选项,它也用于第三种格式,在这种格式中,您使用AWK直接执行文件,即“awk - f文件名”。“-f”选项指定包含指令的AWK文件。如您所见,AWK将以“#”开头的行视为注释,就像shell一样。准确地说,从“#”到行尾的任何内容都是注释(除非它在AWK字符串中)。但是,我总是在行首用“#”来注释AWK脚本,原因我将在后面讨论。

应该使用哪种格式?如果可能的话,我更喜欢最后一种格式。它更短更简单。调试问题也更容易。如果您需要使用shell,并且希望避免使用太多的文件,您可以像我们在第一个和第二个示例中所做的那样组合它们。

用哪种shell搭配AWK?

原始AWK的格式不是自由格式的。你不能把换行符放在任何地方。他们必须去特定的地方。确切地说,在最初的AWK中,您可以在大括号后面和命令末尾插入一个新行字符,但不能在其他地方插入。如果你想在任何地方把一条长线分成两行,你必须使用反斜杠(awk_example2.awk):

#!/bin/awk -f
BEGIN { print "File\tOwner" }
{ print $8, "\t", \ 
$3} 
END { print " - DONE -" }

Bourne shell版本是( awk_example2.sh):

#!/bin/sh
awk '
BEGIN   { print "File\tOwner" }
{ print $8, "\t", \
$3}
END { print "done"} 
'

C shell版本是( awk_example2.csh):

#!/bin/csh -f
awk '
BEGIN   { print "File\tOwner" }\
{ print $8, "\t", \\
$3}\
END { print "done"}\
'

正如您所看到的,这演示了C shell在封装AWK脚本时是多么笨拙。不仅每一行都需要反斜杠,有些行需要两个斜杠,然后使用原来的AWK。更新的AWK更灵活,可以添加新行。
很多人,像我一样,会警告你注意C shell。有些问题很微妙,你可能永远也看不到。尝试在C shell脚本中包含AWK或sed脚本,而反斜杠会让您发疯。这就是多年前说服我学习Bourne shell的原因,当时我刚开始学习(在Korn shell或Bash shell可用之前)。即使您坚持使用C shell,至少也应该学习足够多的Borne/POSIX shell来设置变量,由于某种奇怪的巧合,这将是下一节的主题。

动态变量

因为您可以通过把"#!/bin/awk -f"写在第一行中使脚本可执行,所以不需要在shell脚本中包含AWK脚本,除非您希望消除对额外文件的需要,或者希望将变量传递到AWK脚本的内部。由于这是一个常见的问题,现在正是解释该技术的好时机。我将通过显示一个只打印一列的简单AWK程序来实现这一点。注意:第一个版本会有一个bug。 列的数目将由第一个参数指定。程序的第一个版本的名字我们称之为“列”,看起来是这样的:

#!/bin/sh
#NOTE - this script does not work!
column=$1
awk '{print $column}'

建议的用法是:

ls -l | Column 3

未完待续...

链接

http://www.grymoire.com/Unix/Awk.html

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • 一、systemd的新特性及unit常见类型 systemd即为system daemon,是Centos 7上用...
    烟雨江南_e5eb阅读 1,085评论 0 0
  • 转载 原文的排版和内容都更加友好,并且详细,我只是在这里贴出了一部分留作自己以后参考和学习,如希望更详细了解AWK...
    XKirk阅读 3,185评论 2 25
  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,718评论 0 10
  • 本文参考awk英文Tutorial和三十分钟学会awk[https://github.com/mylxsw/gro...
    蜘蛛鱼阅读 314评论 0 0
  • 一. AWK 说明 awk的处理文本和数据的方式:它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并...
    西华子阅读 923评论 0 4