Linux 中的 awk 命令及示例

评论 0 浏览 0 2020-04-15

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
|-----------------------------------------| 
                    $0                     --> record

Awk 程序

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

pattern { action }
pattern { action }
...

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

awk 操作包含在大括号 ({}) 中并由语句组成。每个语句指定要执行的操作。一项操作可以包含多个由换行符或分号 (;) 分隔的语句。如果规则没有操作,则默认打印整个记录。

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

关系表达式模式

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

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

例如,要打印第二个字段包含“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模式用于处理记录中的数据,例如计算。

以下示例将打印“开始处理。”,然后打印每条记录的第三个字段,最后打印“结束处理。”:

awk 'BEGIN { print "Start Processing." }; { print $3 }; END { print "End Processing." }' teams.txt

输出

Start Processing
60
58
51
49
48
End Processing.

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

Gnu 版本的 awk 还包括两个更特殊的模式 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 操作

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

awk 支持多种类型的操作语句:

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

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
awk -v n="$num" 'BEGIN {print n}'

输出

51

结论

Awk 是最强大的文本操作工具之一。

本文仅涉及 awk 编程语言的皮毛。要了解有关 awk 的更多信息,请查看官方Gawk 文档

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

最后更新2023-09-24
0 个评论
标签