Awk是一种用于高级文本处理的通用脚本语言。 它主要用作报告和分析工具。与大多数其他程序性编程语言不同,awk是数据驱动的,这意味着您定义了一组针对输入文本要执行的操作。 它获取输入数据,对其进行转换,然后将结果发送到标准输出。

本教程介绍了awk编程语言的基本知识。 了解awk的基础知识将大大提高您在命令行上操作文本文件的能力。包括awk的实现gawk,Awk命令的语法和选项,记录和字段的关系,执行awk程序,Awk的正则表达式,关系,范围,特殊,组合模式等,内置变量,更改字段和记录的分隔符,Awk action操作,在Awk程序中使用Shell变量等。

Awk的实现

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

记录和字段

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

记录由字段分隔符分隔的字段组成。 默认情况下,字段之间用空格分隔,包括一个或多个制表符,空格等,你可以通过-F选项指定字段的分隔符。

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

以下直观的展示了记录和字段的关系,也是awk处理文本数据默认使用的记录分隔符-即换行符,字段分隔符-空格符:

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

Awk命令

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

pattern { action }
pattern { action }
...

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

awk action用花括号({})括起来,并由多个语句组成。 每个语句指定要执行的操作。 一个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的文件作为awk的输入,该文件内容如下所示:

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支持不同类型的模式,包括正则表达式,关系表达式,范围和特殊表达式模式。当没有模式时,将匹配每个输入的记录。

下面是仅包含action操作的示例,没有模式:

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

关系表达模式

关系表达式模式通常用于匹配特定字段或变量的内容。默认情况下,正则表达式模式与记录进行匹配。 要将正则表达式与字段进行匹配,请指定该字段并针对模式使用包含比较运算符(~)约等于号。

例如,要仅打印第二个字段包含“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

范围模式

范围模式由用逗号分隔的两个模式组成,从匹配第一个模式的记录开始,直到匹配第二个模式的记录停止匹配,也就是说匹配两个模式之间的记录都会被执行action操作:

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操作括在大括号({})中,并在模式匹配时执行。 一个操作可以有零个或多个语句。 多个语句按照它们出现的先后顺序执行,并且必1须用换行符或分号分隔(;)。

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

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

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

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

awk -f prg.awk

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

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

保存文件并使其可执行

chmod +x prg.awk

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

./prg.awk

在Awk程序中使用Shell变量

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

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

num=51
awk -v n="$num" 'BEGIN {print n}'
51

结论

Awk是最强大的文本处理工具之一。本文几乎没有触及awk编程语言所有知识。 要了解有关awk的更多信息,请查看官方Gawk文档。如果您有任何问题或反馈,请随时发表评论。