Awk是一种用于高级文本处理的通用脚本语言。 它主要用作报告和分析工具。

与大多数其他程序性编程语言不同,awk是数据驱动的,这意味着您定义了一组针对输入文本要执行的操作。 它获取输入数据,对其进行转换,然后将结果发送到标准输出。

本文介绍了awk编程语言的基本知识。 了解awk的基础知识将大大提高您在命令行上操作文本文件的能力。

Awk运作方式

awk有几种不同的实现。 我们将使用awk的GNU实现,称为gawk。 在大多数Linux系统上,awk解释器只是gawk的符号链接。

记录和字段

Awk可以处理文本数据和流。 输入数据分为记录和字段。 Awk一次对一条记录进行操作,直到达到输入结束为止。 记录由称为记录分隔符的字符分隔。 默认的记录分隔符是换行符,这意味着文本数据中的每一行都是一条记录。 可以使用RS变量来设置新的记录分隔符。

记录由字段分隔符分隔的字段组成。 默认情况下,字段之间用空格分隔,包括一个或多个制表符,空格和换行符。

每条记录中的字段均以美元符号($)开头,后跟字段编号,从1开始。第一个字段由$1表示,第二个字段由$2表示,依此类推。 最后一个字段也可以用特殊变量$NF引用。 整个记录可以用$0

以下是直观的图片,展示了如何引用记录和字段:

tmpfs      788M  1.8M  786M   1% /run/lock 
/dev/sda1  234G  191G   31G  87% /
|-------|  |--|  |--|   |--| |-| |--------| 
   $1       $2    $3     $4   $5  $6 ($NF) --> fields $1,$2...字段
|-----------------------------------------| 
                    $0                     --> record 多个字段组成的单行记录

Awk命令程序

要使用awk处理文本,请编写一个程序来告诉命令该做什么。 该程序由一系列规则和用户定义的功能组成。 每个规则包含一个模式和一个动作。 规则用换行符或分号分隔(;)。 通常,awk命令如下所示:

pattern { action }
pattern { action }
...

awk处理数据时,如果模式与记录匹配,则它将对该记录执行指定的操作。 当规则没有模式时,所有记录(行)都匹配。

awk action动作用花括号({})括起来,并由多个语句组成。 每个语句指定要执行的操作。 一个动作可以有多个语句,用换行符或分号隔开(;)。 如果规则无效,则默认为打印整个记录。

Awk支持不同类型的语句,包括表达式,条件,输入,输出语句等。 最常见的awk语句是:

  • exit-停止执行整个程序并退出。
  • next -停止处理当前记录,并移至输入数据中的下一个记录。
  • print -打印记录,字段,变量和自定义文本。
  • printf -使您可以更好地控制输出格式,类似于C和bash printf

编写awk程序时,井号(#)之后直至该行末的所有内容均被视为注释。 可以使用反斜杠(\)将长行分成多行。

执行awk程序

awk程序可以通过多种方式运行。 如果程序简短而简单,则可以将其直接通过命令行传递给awk解释器:

awk 'program' input-file...

在命令行上运行程序时,应将其括在单引号('')中,以便shell程序解释程序。

如果程序又大又复杂,最好将其放入文件中,并使用-f选项将文件传递给awk命令:

awk -f program-file input-file...

在以下示例中,我们将使用一个名为“ teams.txt”的文件,该文件如下所示:

Bucks Milwaukee    60 22 0.732 
Raptors Toronto    58 24 0.707 
76ers Philadelphia 51 31 0.622
Celtics Boston     49 33 0.598
Pacers Indiana     48 34 0.585

Awk模式

awk中的模式控制是否应执行关联的动作。

Awk支持不同类型的模式,包括正则表达式,关系表达式,范围和特殊表达式模式。

当规则没有模式时,将匹配每个输入记录。 这是仅包含操作的规则的示例:

awk '{ print $3 }' teams.txt

程序将打印每条记录的第三个字段:

60
58
51
49
48

正则表达式模式

正则表达式是与一组字符串匹配的模式。 Awk正则表达式模式包含在斜杠(//)中:

/regex pattern/ { action }

最基本的示例是文字字符或字符串匹配。 例如,要显示每个包含“ 0.5”的记录的第一个字段,您可以运行以下命令:

awk '/0.5/ { print $1 }' teams.txt
Celtics
Pacers

模式可以是任何类型的扩展正则表达式。 这是一个示例,如果记录以两个或多个数字开头,则打印第一个字段:

awk '/^[0-9][0-9]/ { print $1 }' teams.txt
76ers

关系表达模式

关系表达式模式通常用于匹配特定字段或变量的内容。

默认情况下,正则表达式模式与记录匹配。 要将正则表达式与字段匹配,请指定该字段并针对模式使用“contain”包含比较运算符(~)。

例如,要打印第二个字段包含“ ia”的每个记录的第一个字段,请输入:

awk '$2 ~ /ia/ { print $1 }' teams.txt
76ers
Pacers

要匹配不包含指定模式的字段,请使用!~运算符:

awk '$2 !~ /ia/ { print $1 }' teams.txt
Bucks
Raptors
Celtics

您可以比较字符串或数字之间的关系,例如,大于,小于,等于等。 以下命令将打印第三字段大于50的所有记录的第一字段:

awk '$3 > 50 { print $1 }' teams.txt
Bucks
Raptors
76ers

范围模式

范围模式由用逗号分隔的两个模式组成:

pattern1, pattern2

从匹配第一个模式的记录开始的所有记录,直到匹配第二个模式的记录为止。

以下是一个示例,该示例将从包括“Raptors”的记录到包括“Celtics”的记录开始打印所有记录的第一个字段:

awk '/Raptors/,/Celtics/ { print $1 }' teams.txt
Raptors
76ers
Celtics

模式也可以是关系表达式。 下面的命令将打印所有记录,从第四个字段等于32的记录开始,直到第四个字段等于33的记录:

awk '$4 == 31, $4 == 33 { print $0 }' teams.txt
76ers Philadelphia 51 31 0.622
Celtics Boston     49 33 0.598

范围模式不能与其他模式表达式组合。

特殊表达模式

Awk包括以下特殊模式:

  • BEGIN-用于在处理记录之前执行操作。
  • END -用于在处理记录后执行操作。

BEGIN模式通常用于设置变量,END模式通常用于处理记录中的数据,例如计算。

以下示例将打印“Start Processing.”,然后打印每个记录的第三个字段,最后打印“End Processing.”。

awk 'BEGIN { print "Start Processing." }; { print $3 }; END { print "End Processing." }' teams.txt
Start Processing
60
58
51
49
48
End Processing.

如果程序只有BEGIN模式,则执行操作,并且不处理输入。 如果程序只有END模式,则在执行规则操作之前先处理输入。

awk的Gnu版本还包括另外两个特殊模式BEGINFILEENDFILE,它们允许您在处理文件时执行操作。

组合模式

Awk允许您使用逻辑AND运算符(&&)和逻辑OR运算符(||)组合两个或多个模式。

这里是一个示例,该示例使用&&运算符来打印第三字段大于50而第四字段小于30的那些记录的第一字段:

awk '$3 > 50 && $4 < 30 { print $1 }' teams.txt
Bucks
Raptors

内置变量

Awk具有许多内置变量,这些变量包含非常有用的信息,并允许您控制程序的处理方式。 以下是一些最常见的内置变量:

  • NF-记录中的字段数。
  • NR -当前记录的编号。
  • FILENAME -当前正在处理的输入文件的名称。
  • FS -分隔符。
  • RS -记录分隔符。
  • OFS -输出字段分隔符。
  • ORS -输出记录分隔符。

以下是显示如何打印文件名和行数(记录)的示例:

awk 'END { print "File", FILENAME, "contains", NR, "lines." }' teams.txt
File teams.txt contains 5 lines.

AWK中的变量可以在程序的任何行中设置。 要为整个程序定义变量,请将其置于BEGIN模式中。

更改字段和记录分隔符

字段分隔符的默认值为任意数量的空格或制表符。 可以通过在FS变量中进行设置来更改。

例如,要将字段分隔符设置为.,请使用:

awk 'BEGIN { FS = "." } { print $1 }' teams.txt
Bucks Milwaukee    60 22 0
Raptors Toronto    58 24 0
76ers Philadelphia 51 31 0
Celtics Boston     49 33 0
Pacers Indiana     48 34 0

字段分隔符也可以设置为多个字符:

awk 'BEGIN { FS = ".." } { print $1 }' teams.txt

在命令行上运行awk单行代码时,您还可以使用-F选项更改字段分隔符:

awk -F "." '{ print $1 }' teams.txt

默认情况下,记录分隔符是换行符,可以使用RS变量进行更改。

以下是显示如何将记录分隔符更改为.的示例:

awk 'BEGIN { RS = "." } { print $1 }' teams.txt
Bucks Milwaukee    60 22 0
732 
Raptors Toronto    58 24 0
707 
76ers Philadelphia 51 31 0
622
Celtics Boston     49 33 0
598
Pacers Indiana     48 34 0
585

Awk action动作

Awk action动作括在大括号({})中,并在模式匹配时执行。 一个动作可以有零个或多个语句。 多个语句按照它们出现的顺序执行,并且必须用换行符或分号分隔(;)。

awk支持几种类型的动作语句:

  • 表达式,例如变量赋值,算术运算符,增量和减量运算符。
  • 控制语句,用于控制程序的流程(ifforwhileswitch等)
  • 输出语句,例如printprintf
  • 复合语句,可将其他语句分组。
  • 输入语句 ,以控制输入的处理。
  • Deletion语句,删除数组元素。

print语句可能是最常用的awk语句。 它打印文本,记录,字段和变量的格式化输出。

打印多个项目时,需要用逗号分隔。 这是一个例子:

awk '{ print $1, $3, $5 }' teams.txt

打印的字段用单个空格分隔:

Bucks 60 0.732
Raptors 58 0.707
76ers 51 0.622
Celtics 49 0.598
Pacers 48 0.585

如果您不使用逗号,则字段之间将没有空格:

awk '{ print $1 $3 $5 }' teams.txt

这些字段是串联在一起的:

Bucks600.732
Raptors580.707
76ers510.622
Celtics490.598
Pacers480.585

如果不带参数使用print,则默认为print $0。 打印当前记录。

要打印自定义文本,必须用双引号引起来的文本:

awk '{ print "The first field:", $1}' teams.txt
The first field: Bucks
The first field: Raptors
The first field: 76ers
The first field: Celtics
The first field: Pacers

您还可以打印特殊字符,例如换行符:

awk 'BEGIN { print "First line\nSecond line\nThird line" }'
First line
Second line
Third line

printf语句使您可以更好地控制输出格式。 这是一个插入行号的示例:

awk '{ printf "%3d. %s\n", NR, $0 }' teams.txt

printf不会在每条记录后创建换行符,因此我们使用\n

  1. Bucks Milwaukee    60 22 0.732 
  2. Raptors Toronto    58 24 0.707 
  3. 76ers Philadelphia 51 31 0.622
  4. Celtics Boston     49 33 0.598
  5. Pacers Indiana     48 34 0.585

以下命令计算每行第三字段中存储的值的总和:

awk '{ sum += $3 } END { printf "%d\n", sum }' teams.txt
266

这是另一个示例,显示了如何使用表达式和控制语句来打印从1到5的数字的平方:

awk 'BEGIN { i = 1; while (i < 6) { print "Square of", i, "is", i*i; ++i } }'
Square of 1 is 1
Square of 2 is 4
Square of 3 is 9
Square of 4 is 16
Square of 5 is 25

诸如上述的单行命令更难理解和维护。 在编写更长的程序时,您应该创建一个单独的程序文件:

prg.awk

BEGIN { 
  i = 1
  while (i < 6) { 
    print "Square of", i, "is", i*i; 
    ++i 
  } 
}

通过将文件名传递给awk解释器来运行程序:

awk -f prg.awk

您还可以通过使用 shebang 指令并设置awk解释器,将awk程序作为可执行文件运行:

prg.awk

#!/usr/bin/awk -f
BEGIN { 
  i = 1
  while (i < 6) { 
    print "Square of", i, "is", i*i; 
    ++i 
  } 
}

保存文件并使其可执行

chmod +x prg.awk

您现在可以通过输入以下内容来运行程序:

./prg.awk

在Awk程序中使用Shell变量

如果您在Shell程序脚本中使用awk命令,则很可能需要将Shell程序变量传递给awk程序。 一种选择是用双引号而不是单引号将程序引起来,并在程序中替换变量。 但是,此选项会使您的awk程序更加复杂,因为您需要对awk变量进行转义。

在awk程序中使用shell变量的推荐方法是将shell变量分配给awk变量。 这是一个例子:

num=51
51

结论

Awk是最强大的文本处理工具之一。

本文几乎没有触及awk编程语言的表面。 要了解有关awk的更多信息,请查看官方 Gawk文档

如果您有任何问题或反馈,请随时发表评论。