AWK - 快速指南


AWK - 概述

AWK 是一种解释型编程语言。它非常强大,专门为文本处理而设计。它的名字源自其作者的姓氏——阿尔弗雷德·阿霍 (Alfred Aho)、彼得·温伯格 (Peter Weinberger) 和布莱恩·科尼汉 (Brian Kernighan)。

GNU/Linux 发行的 AWK 版本由自由软件基金会 (FSF) 编写和维护;它通常被称为GNU AWK。

AWK 的类型

以下是 AWK 的变体 -

  • AWK - 来自 AT & T 实验室的原始 AWK。

  • NAWK - AT&T 实验室 AWK 的更新和改进版本。

  • GAWK - 它是 GNU AWK。所有 GNU/Linux 发行版都附带 GAWK。它与 AWK 和 NAWK 完全兼容。

AWK 的典型用途

使用 AWK 可以完成无数任务。下面列出的只是其中的一些 -

  • 文本处理,
  • 生成格式化的文本报告,
  • 执行算术运算,
  • 执行字符串操作等等。

AWK - 环境

本章介绍如何在 GNU/Linux 系统上设置 AWK 环境。

使用包管理器安装

一般来说,AWK 在大多数 GNU/Linux 发行版上默认可用。您可以使用which命令来检查它是否存在于您的系统上。如果您没有 AWK,请使用 Advance Package Tool (APT)包管理器将其安装在基于 Debian 的 GNU/Linux 上,如下所示 -

[jeryy]$ sudo apt-get update
[jeryy]$ sudo apt-get install gawk

同样,要在基于 RPM 的 GNU/Linux 上安装 AWK,请使用 Yellowdog Updator Modifier yum包管理器,如下所示 -

[root]# yum install gawk

安装后,确保可以通过命令行访问 AWK。

[jerry]$ which awk

执行上面的代码,你会得到以下结果 -

/usr/bin/awk

从源代码安装

由于 GNU AWK 是 GNU 项目的一部分,因此其源代码可以免费下载。我们已经了解了如何使用包管理器安装 AWK。现在让我们了解如何从源代码安装 AWK。

以下安装适用于任何 GNU/Linux 软件,以及大多数其他免费程序。以下是安装步骤 -

步骤 1 - 从真实的地方下载源代码。命令行实用程序wget可以用于此目的。

[jerry]$ wget http://ftp.gnu.org/gnu/gawk/gawk-4.1.1.tar.xz

步骤 2 - 解压缩并提取下载的源代码。

[jerry]$ tar xvf gawk-4.1.1.tar.xz

步骤 3 - 切换到目录并运行配置。

[jerry]$ ./configure

步骤 4 - 成功完成后,配置会生成 Makefile。要编译源代码,请发出make命令。

[jerry]$ make

步骤 5 - 您可以运行测试套件以确保构建是干净的。这是一个可选步骤。

[jerry]$ make check

步骤 6 - 最后,安装 AWK。确保您拥有超级用户权限。

[jerry]$ sudo make install

这就对了!您已成功编译并安装 AWK。通过执行awk命令来验证它,如下所示 -

[jerry]$ which awk

执行此代码时,您将得到以下结果 -

/usr/bin/awk

AWK-工作流程

要成为 AWK 程序员专家,您需要了解其内部结构。AWK 遵循简单的工作流程 - 读取、执行和重复。下图描述了 AWK 的工作流程 -

AWK工作流程

AWK 从输入流(文件、管道或标准输入)读取一行并将其存储在内存中。

执行

所有 AWK 命令都按顺序应用于输入。默认情况下,AWK 在每一行执行命令。我们可以通过提供模式来限制这一点。

重复

重复此过程直到文件到达末尾。

程序结构

现在让我们了解一下AWK的程序结构。

开始块

BEGIN 块的语法如下 -

句法

BEGIN {awk-commands}

BEGIN 块在程序启动时执行。它只执行一次。这是初始化变量的好地方。BEGIN 是 AWK 关键字,因此它必须为大写。请注意,此块是可选的。

身体块

主体块的语法如下 -

句法

/pattern/ {awk-commands}

主体块在每个输入行上应用 AWK 命令。默认情况下,AWK 在每一行上执行命令。我们可以通过提供模式来限制这一点。请注意,Body 块没有关键字。

结束块

END 块的语法如下 -

句法

END {awk-commands}

END 块在程序结束时执行。END 是 AWK 关键字,因此它必须为大写。请注意,此块是可选的。

让我们创建一个文件marks.txt,其中包含序列号、学生姓名、科目名称和获得的分数。

1)  Amit    Physics  80
2)  Rahul   Maths    90
3)  Shyam   Biology  87
4)  Kedar   English  85
5)  Hari    History  89

现在让我们使用 AWK 脚本显示带有标题的文件内容。

例子

[jerry]$ awk 'BEGIN{printf "Sr No\tName\tSub\tMarks\n"} {print}' marks.txt

执行此代码时,会产生以下结果 -

输出

Sr No Name Sub Marks
1) Amit Physics 80
2) Rahul Maths 90
3) Shyam Biology 87
4) Kedar English 85
5) Hari History 89

首先,AWK 打印 BEGIN 块中的标头。然后在主体块中,它从文件中读取一行并执行 AWK 的打印命令,该命令仅在标准输出流上打印内容。重复此过程直到文件到达末尾。

AWK - 基本语法

AWK 使用起来很简单。我们可以直接从命令行提供 AWK 命令,也可以以包含 AWK 命令的文本文件的形式提供 AWK 命令。

AWK 命令行

我们可以在命令行的单引号内指定 AWK 命令,如下所示 -

awk [options] file ...

例子

考虑一个包含以下内容的文本文件marks.txt -

1) Amit     Physics    80
2) Rahul    Maths      90
3) Shyam    Biology    87
4) Kedar    English    85
5) Hari     History    89

让我们使用 AWK 显示文件的完整内容,如下所示 -

例子

[jerry]$ awk '{print}' marks.txt 

执行此代码时,您将得到以下结果 -

输出

1) Amit     Physics    80
2) Rahul    Maths      90
3) Shyam    Biology    87
4) Kedar    English    85
5) Hari     History    89

AWK 程序文件

我们可以在脚本文件中提供 AWK 命令,如下所示 -

awk [options] -f file ....

首先,创建一个包含 AWK 命令的文本文件command.awk,如下所示 -

{print}

现在我们可以指示 AWK 从文本文件中读取命令并执行操作。在这里,我们获得了与上例所示相同的结果。

例子

[jerry]$ awk -f command.awk marks.txt

执行此代码时,您将得到以下结果 -

输出

1) Amit  Physics 80
2) Rahul Maths   90
3) Shyam Biology 87
4) Kedar English 85
5) Hari  History 89

AWK 标准选项

AWK 支持以下可以从命令行提供的标准选项。

-v 选项

该选项为变量赋值。它允许在程序执行之前进行赋值。以下示例描述了 -v 选项的用法。

例子

[jerry]$ awk -v name=Jerry 'BEGIN{printf "Name = %s\n", name}'

执行此代码时,您将得到以下结果 -

输出

Name = Jerry

--dump-variables[=文件] 选项

它打印全局变量的排序列表及其最终值到文件。默认文件是awkvars.out

例子

[jerry]$ awk --dump-variables ''
[jerry]$ cat awkvars.out 

执行上面的代码,你会得到以下结果 -

输出

ARGC: 1
ARGIND: 0
ARGV: array, 1 elements
BINMODE: 0
CONVFMT: "%.6g"
ERRNO: ""
FIELDWIDTHS: ""
FILENAME: ""
FNR: 0
FPAT: "[^[:space:]]+"
FS: " "
IGNORECASE: 0
LINT: 0
NF: 0
NR: 0
OFMT: "%.6g"
OFS: " "
ORS: "\n"
RLENGTH: 0
RS: "\n"
RSTART: 0
RT: ""
SUBSEP: "\034"
TEXTDOMAIN: "messages"

--help 选项

此选项在标准输出上打印帮助消息。

例子

[jerry]$ awk --help

执行此代码时,您将得到以下结果 -

输出

Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options : GNU long options: (standard)
   -f progfile                --file=progfile
   -F fs                      --field-separator=fs
   -v var=val                 --assign=var=val
Short options : GNU long options: (extensions)
   -b                         --characters-as-bytes
   -c                         --traditional
   -C                         --copyright
   -d[file]                   --dump-variables[=file]
   -e 'program-text'          --source='program-text'
   -E file                    --exec=file
   -g                         --gen-pot
   -h                         --help
   -L [fatal]                 --lint[=fatal]
   -n                         --non-decimal-data
   -N                         --use-lc-numeric
   -O                         --optimize
   -p[file]                   --profile[=file]
   -P                         --posix
   -r                         --re-interval
   -S                         --sandbox
   -t                         --lint-old
   -V                         --version

--lint[=致命] 选项

此选项可以检查不可移植或可疑的结构。当提供参数fatal时,它将警告消息视为错误。以下示例演示了这一点 -

例子

[jerry]$ awk --lint '' /bin/ls

执行此代码时,您将得到以下结果 -

输出

awk: cmd. line:1: warning: empty program text on command line
awk: cmd. line:1: warning: source file does not end in newline
awk: warning: no program text at all!

--posix 选项

此选项打开严格的 POSIX 兼容性,其中所有常见的和特定于 gawk 的扩展都被禁用。

--profile[=文件] 选项

此选项会在文件中生成程序的精美打印版本。默认文件是awkprof.out。下面的简单例子说明了这一点 -

例子

[jerry]$ awk --profile 'BEGIN{printf"---|Header|--\n"} {print} 
END{printf"---|Footer|---\n"}' marks.txt > /dev/null 
[jerry]$ cat awkprof.out

执行此代码时,您将得到以下结果 -

输出

# gawk profile, created Sun Oct 26 19:50:48 2014

   # BEGIN block(s)

   BEGIN {
      printf "---|Header|--\n"
   }

   # Rule(s) {
      print $0
   }

   # END block(s)

   END {
      printf "---|Footer|---\n"
   }

--traditional 选项

此选项禁用所有特定于 gawk 的扩展。

--version 选项

该选项显示 AWK 程序的版本信息。

例子

[jerry]$ awk --version

执行此代码时,会产生以下结果 -

输出

GNU Awk 4.0.1
Copyright (C) 1989, 1991-2012 Free Software Foundation.

AWK - 基本示例

本章介绍了几个有用的 AWK 命令及其相应的示例。考虑使用以下内容处理文本文件marks.txt -

1) Amit     Physics   80
2) Rahul    Maths     90
3) Shyam    Biology   87
4) Kedar    English   85
5) Hari     History   89

打印列或字段

您可以指示 AWK 仅打印输入字段中的某些列。以下示例演示了这一点 -

例子

[jerry]$ awk '{print $3 "\t" $4}' marks.txt

执行此代码时,您将得到以下结果 -

输出

Physics   80
Maths     90
Biology   87
English   85
History   89

在文件marks.txt中,第三列包含主题名称,第四列包含在特定主题中获得的分数。让我们使用 AWK 打印命令打印这两列。在上面的示例中,$3 和 $4分别表示输入记录中的第三个和第四个字段。

打印所有行

默认情况下,AWK 打印所有与模式匹配的行。

例子

[jerry]$ awk '/a/ {print $0}' marks.txt

执行此代码时,您将得到以下结果 -

输出

2) Rahul    Maths     90
3) Shyam    Biology   87
4) Kedar    English   85
5) Hari     History   89

在上面的示例中,我们正在搜索表单模式a。当模式匹配成功时,它会执行主体块中的命令。在没有正文块的情况下 - 采取默认操作,即打印记录。因此,以下命令会产生相同的结果 -

例子

[jerry]$ awk '/a/' marks.txt

按模式打印列

当模式匹配成功时,AWK 默认打印整个记录。但您可以指示 AWK 仅打印某些字段。例如,以下示例在模式匹配成功时打印第三个和第四个字段。

例子

[jerry]$ awk '/a/ {print $3 "\t" $4}' marks.txt

执行此代码时,您将得到以下结果 -

输出

Maths    90
Biology  87
English  85
History  89

以任意顺序打印列

您可以按任何顺序打印列。例如,以下示例打印第四列,然后打印第三列。

例子

[jerry]$ awk '/a/ {print $4 "\t" $3}' marks.txt

执行上面的代码,你会得到以下结果 -

输出

90   Maths
87   Biology
85   English
89   History

计数并打印匹配的图案

让我们看一个示例,您可以在其中计算并打印模式匹配成功的行数。

例子

[jerry]$ awk '/a/{++cnt} END {print "Count = ", cnt}' marks.txt

执行此代码时,您将得到以下结果 -

输出

Count = 4

在此示例中,当模式匹配成功时,我们增加计数器的值,并在 END 块中打印该值。请注意,与其他编程语言不同,在使用变量之前无需声明变量。

打印超过 18 个字符的行

让我们只打印那些包含超过 18 个字符的行。

例子

[jerry]$ awk 'length($0) > 18' marks.txt

执行此代码时,您将得到以下结果 -

输出

3) Shyam   Biology   87
4) Kedar   English   85

AWK 提供了一个内置的长度 函数,用于返回字符串的长度。$0变量存储整行,并且在没有主体块的情况下,将采取默认操作,即打印操作。因此,如果一行超过 18 个字符,则比较结果为 true,并且该行将被打印。

AWK - 内置变量

AWK 提供了几个内置变量。它们在编写 AWK 脚本时发挥着重要作用。本章演示了内置变量的用法。

标准 AWK 变量

标准 AWK 变量将在下面讨论。

ARGC

它意味着命令行中提供的参数数量。

例子

[jerry]$ awk 'BEGIN {print "Arguments =", ARGC}' One Two Three Four

执行此代码时,您将得到以下结果 -

输出

Arguments = 5

但是为什么当你只传递 4 个参数时 AWK 显示 5 呢?只需查看以下示例即可消除您的疑虑。

ARGV

它是一个存储命令行参数的数组。该数组的有效索引范围为 0 到 ARGC-1。

例子

[jerry]$ awk 'BEGIN { 
   for (i = 0; i < ARGC - 1; ++i) { 
      printf "ARGV[%d] = %s\n", i, ARGV[i] 
   } 
}' one two three four

执行此代码时,您将得到以下结果 -

输出

ARGV[0] = awk
ARGV[1] = one
ARGV[2] = two
ARGV[3] = three

卷积FMT

它代表数字的转换格式。它的默认值为%.6g

例子

[jerry]$ awk 'BEGIN { print "Conversion Format =", CONVFMT }'

执行此代码时,您将得到以下结果 -

输出

Conversion Format = %.6g

环境

它是环境变量的关联数组。

例子

[jerry]$ awk 'BEGIN { print ENVIRON["USER"] }'

执行此代码时,您将得到以下结果 -

输出

jerry

要查找其他环境变量的名称,请使用env命令。

文件名

它代表当前文件名。

例子

[jerry]$ awk 'END {print FILENAME}' marks.txt

执行此代码时,您将得到以下结果 -

输出

marks.txt

请注意,BEGIN 块中未定义 FILENAME。

FS

它表示(输入)字段分隔符,其默认值为空格。您还可以使用-F命令行选项来更改此设置。

例子

[jerry]$ awk 'BEGIN {print "FS = " FS}' | cat -vte

执行此代码时,您将得到以下结果 -

输出

FS =  $

核因子

它表示当前记录中的字段数。例如,以下示例仅打印包含两个以上字段的行。

例子

[jerry]$ echo -e "One Two\nOne Two Three\nOne Two Three Four" | awk 'NF > 2'

执行此代码时,您将得到以下结果 -

输出

One Two Three
One Two Three Four

NR

它代表当前记录的数量。例如,如果当前记录数小于 3,以下示例将打印该记录。

例子

[jerry]$ echo -e "One Two\nOne Two Three\nOne Two Three Four" | awk 'NR < 3'

执行此代码时,您将得到以下结果 -

输出

One Two
One Two Three

FNR

它与NR类似,但相对于当前文件。当 AWK 操作多个文件时它很有用。FNR 的值随新文件重置。

正交频域调制

它表示输出格式编号,默认值为%.6g

例子

[jerry]$ awk 'BEGIN {print "OFMT = " OFMT}'

执行此代码时,您将得到以下结果 -

输出

OFMT = %.6g

欧福斯

它表示输出字段分隔符,默认值为空格。

例子

[jerry]$ awk 'BEGIN {print "OFS = " OFS}' | cat -vte

执行此代码时,您将得到以下结果 -

输出

OFS =  $

口服补液盐

表示输出记录分隔符,默认值为换行符。

例子

[jerry]$ awk 'BEGIN {print "ORS = " ORS}' | cat -vte

执行上面的代码,你会得到以下结果 -

输出

ORS = $
$

长度

表示match函数匹配到的字符串的长度。AWK 的匹配函数在输入字符串中搜索给定的字符串。

例子

[jerry]$ awk 'BEGIN { if (match("One Two Three", "re")) { print RLENGTH } }'

执行此代码时,您将得到以下结果 -

输出

2

RS

它代表(输入)记录分隔符,默认值为换行符。

例子

[jerry]$ awk 'BEGIN {print "RS = " RS}' | cat -vte

执行此代码时,您将得到以下结果 -

输出

RS = $
$

启动程序

它表示由match函数匹配的字符串中的第一个位置。

例子

[jerry]$ awk 'BEGIN { if (match("One Two Three", "Thre")) { print RSTART } }'

执行此代码时,您将得到以下结果 -

输出

9

子集

它表示数组下标的分隔符,默认值为\034

例子

[jerry]$ awk 'BEGIN { print "SUBSEP = " SUBSEP }' | cat -vte

执行此代码时,您将得到以下结果 -

输出

SUBSEP = ^\$

$0

它代表整个输入记录。

例子

[jerry]$ awk '{print $0}' marks.txt

执行此代码时,您将得到以下结果 -

输出

1) Amit     Physics   80
2) Rahul    Maths     90
3) Shyam    Biology   87
4) Kedar    English   85
5) Hari     History   89

$n

它表示当前记录中的第 n字段,字段之间用 FS 分隔。

例子

[jerry]$ awk '{print $3 "\t" $4}' marks.txt

执行此代码时,您将得到以下结果 -

输出

Physics   80
Maths     90
Biology   87
English   85
History   89

GNU AWK 特定变量

GNU AWK 特定变量如下 -

阿尔金德

它表示当前正在处理的文件在 ARGV 中的索引。

例子

[jerry]$ awk '{ 
   print "ARGIND   = ", ARGIND; print "Filename = ", ARGV[ARGIND] 
}' junk1 junk2 junk3

执行此代码时,您将得到以下结果 -

输出

ARGIND   =  1
Filename =  junk1
ARGIND   =  2
Filename =  junk2
ARGIND   =  3
Filename =  junk3

宾模式

它用于指定非 POSIX 系统上所有文件 I/O 的二进制模式。数值 1、2 或 3 分别指定输入文件、输出文件或所有文件应使用二进制 I/O。rw的字符串值分别指定输入文件或输出文件应使用二进制 I/O。rwwr的字符串值指定所有文件都应使用二进制 I/O。

错误号

当getline重定向失败或关闭调用失败时,字符串指示错误。

例子

[jerry]$ awk 'BEGIN { ret = getline < "junk.txt"; if (ret == -1) print "Error:", ERRNO }'

执行此代码时,您将得到以下结果 -

输出

Error: No such file or directory

场宽

设置空格分隔的字段宽度变量列表,GAWK 将输入解析为固定宽度的字段,而不是使用 FS 变量的值作为字段分隔符。

忽略大小写

设置此变量后,GAWK 将不区分大小写。以下示例演示了这一点 -

例子

[jerry]$ awk 'BEGIN{IGNORECASE = 1} /amit/' marks.txt

执行此代码时,您将得到以下结果 -

输出

1) Amit  Physics   80

皮棉

它提供了GAWK 程序中--lint选项的动态控制。设置此变量后,GAWK 会打印 lint 警告。当分配字符串值 fatal 时,lint 警告将变为致命错误,与--lint=fatal完全相同。

例子

[jerry]$ awk 'BEGIN {LINT = 1; a}'

执行此代码时,您将得到以下结果 -

输出

awk: cmd. line:1: warning: reference to uninitialized variable `a'
awk: cmd. line:1: warning: statement has no effect

信息处理系统

这是一个关联数组,包含有关进程的信息,例如真实有效的 UID 号、进程 ID 号等。

例子

[jerry]$ awk 'BEGIN { print PROCINFO["pid"] }'

执行此代码时,您将得到以下结果 -

输出

4316

文本域

它代表 AWK 程序的文本域。它用于查找程序字符串的本地化翻译。

例子

[jerry]$ awk 'BEGIN { print TEXTDOMAIN }'

执行此代码时,您将得到以下结果 -

输出

messages

由于en_IN区域设置,上面的输出显示英文文本

AWK - 运算符

与其他编程语言一样,AWK 也提供了大量运算符。本章通过适当的示例解释了 AWK 运算符。

编号 运算符和描述
1 算术运算符

AWK 支持以下算术运算符。

2 自增和自减运算符

AWK 支持以下递增和递减运算符。

3 赋值运算符

AWK 支持以下赋值运算符。

4 关系运算符

AWK 支持以下关系运算符。

5 逻辑运算符

AWK 支持以下逻辑运算符。

6 三元运算符

我们可以使用三元运算符轻松实现条件表达式。

7 一元运算符

AWK 支持以下一元运算符。

8 指数运算符

指数运算符有两种格式。

9 字符串连接运算符

空格是一个字符串连接运算符,用于合并两个字符串。

10 数组成员运算符

它用in表示。它在访问数组元素时使用。

11 正则表达式运算符

此示例解释了正则表达式运算符的两种形式。

AWK - 正则表达式

AWK 在处理正则表达式方面非常强大且高效。许多复杂的任务可以用简单的正则表达式来解决。任何命令行专家都知道正则表达式的强大功能。

本章介绍标准正则表达式以及合适的示例。

它匹配除行尾字符之外的任何单个字符。例如,以下示例匹配fin、fun、fan等。

例子

[jerry]$ echo -e "cat\nbat\nfun\nfin\nfan" | awk '/f.n/'

执行上面的代码,你会得到以下结果 -

输出

fun
fin
fan

行首

它与行的开头匹配。例如,以下示例打印以模式The开头的所有行。

例子

[jerry]$ echo -e "This\nThat\nThere\nTheir\nthese" | awk '/^The/'

执行此代码时,您将得到以下结果 -

输出

There
Their

行结束

它匹配行尾。例如,以下示例打印以字母n结尾的行。

例子

[jerry]$ echo -e "knife\nknow\nfun\nfin\nfan\nnine" | awk '/n$/'

输出

执行此代码时,您将得到以下结果 -

fun
fin
fan

匹配字符集

它用于仅匹配多个字符中的一个。例如,以下示例匹配模式CallTall但不匹配Ball

例子

[jerry]$ echo -e "Call\nTall\nBall" | awk '/[CT]all/'

输出

执行此代码时,您将得到以下结果 -

Call
Tall

独家套装

在独占集中,克拉否定方括号中的字符集。例如,以下示例仅打印Ball

例子

[jerry]$ echo -e "Call\nTall\nBall" | awk '/[^CT]all/'

执行此代码时,您将得到以下结果 -

输出

Ball

改造

竖线允许对正则表达式进行逻辑“或”运算。例如,以下示例打印BallCall

例子

[jerry]$ echo -e "Call\nTall\nBall\nSmall\nShall" | awk '/Call|Ball/'

执行此代码时,您将得到以下结果 -

输出

Call
Ball

零次或一次出现

它匹配零次或一次出现的前一个字符。例如,以下示例匹配Color以及Color我们通过使用?u作为可选字符。。

例子

[jerry]$ echo -e "Colour\nColor" | awk '/Colou?r/'

执行此代码时,您将得到以下结果 -

输出

Colour
Color

零次或多次出现

它匹配零个或多次出现的前一个字符。例如,以下示例匹配ca、cat、catt等。

例子

[jerry]$ echo -e "ca\ncat\ncatt" | awk '/cat*/'

执行此代码时,您将得到以下结果 -

输出

ca
cat
catt

一次或多次出现

它匹配前面字符的一次或多次出现。例如,下面的示例匹配一次或多次出现的2

例子

[jerry]$ echo -e "111\n22\n123\n234\n456\n222"  | awk '/2+/'

执行上面的代码,你会得到以下结果 -

输出

22
123
234
222

分组

括号 ()用于分组,字符 | 用于替代品。例如,以下正则表达式匹配包含Apple Juice 或 Apple Cake的行。

例子

[jerry]$ echo -e "Apple Juice\nApple Pie\nApple Tart\nApple Cake" | awk 
   '/Apple (Juice|Cake)/'

执行此代码时,您将得到以下结果 -

输出

Apple Juice
Apple Cake

AWK - 数组

AWK 具有关联数组,它最好的一点是 – 索引不需要是连续的数字集;您可以使用字符串或数字作为数组索引。此外,无需提前声明数组的大小 - 数组可以在运行时扩展/收缩。

其语法如下 -

句法

array_name[index] = value

其中array_name是数组的名称,index是数组索引,value是分配给数组元素的任何值。

创建数组

为了更深入地了解数组,让我们创建并访问数组的元素。

例子

[jerry]$ awk 'BEGIN {
   fruits["mango"] = "yellow";
   fruits["orange"] = "orange"
   print fruits["orange"] "\n" fruits["mango"]
}'

执行此代码时,您将得到以下结果 -

输出

orange
yellow

在上面的例子中,我们将数组声明为fruits,其索引是水果名称,值是水果的颜色。要访问数组元素,我们使用array_name[index]格式。

删除数组元素

对于插入,我们使用赋值运算符。同样,我们可以使用delete语句从数组中删除一个元素。删除语句的语法如下 -

句法

delete array_name[index]

以下示例删除元素Orange。因此该命令不显示任何输出。

例子

[jerry]$ awk 'BEGIN {
   fruits["mango"] = "yellow";
   fruits["orange"] = "orange";
   delete fruits["orange"];
   print fruits["orange"]
}'

多维数组

AWK 仅支持一维数组。但是您可以使用一维数组本身轻松模拟多维数组。

例如,下面给出的是一个 3x3 二维数组 -

100   200   300
400   500   600
700   800   900

在上面的示例中,array[0][0] 存储 100,array[0][1] 存储 200,依此类推。要将 100 存储在数组位置 [0][0] 处,我们可以使用以下语法 -

句法

array["0,0"] = 100

虽然我们给出了0,0作为索引,但这不是两个索引。实际上,它只是一个带有字符串0,0 的索引。

以下示例模拟二维数组 -

例子

[jerry]$ awk 'BEGIN {
   array["0,0"] = 100;
   array["0,1"] = 200;
   array["0,2"] = 300;
   array["1,0"] = 400;
   array["1,1"] = 500;
   array["1,2"] = 600;

   # print array elements
   print "array[0,0] = " array["0,0"];
   print "array[0,1] = " array["0,1"];
   print "array[0,2] = " array["0,2"];
   print "array[1,0] = " array["1,0"];
   print "array[1,1] = " array["1,1"];
   print "array[1,2] = " array["1,2"];
}'

执行此代码时,您将得到以下结果 -

输出

array[0,0] = 100
array[0,1] = 200
array[0,2] = 300
array[1,0] = 400
array[1,1] = 500
array[1,2] = 600

您还可以对数组执行各种操作,例如对其元素/索引进行排序。为此,您可以使用assortasorti函数

AWK - 控制流

与其他编程语言一样,AWK 提供条件语句来控制程序流程。本章通过适当的示例解释了 AWK 的控制语句。

如果语句

它只是测试条件并根据条件执行某些操作。下面给出的是if语句的语法-

句法

if (condition)
   action

我们还可以使用下面给出的一对大括号来执行多个操作 -

句法

if (condition) {
   action-1
   action-1
   .
   .
   action-n
}

例如,以下示例检查数字是否为偶数 -

例子

[jerry]$ awk 'BEGIN {num = 10; if (num % 2 == 0) printf "%d is even number.\n", num }'

执行上面的代码,你会得到以下结果 -

输出

10 is even number.

如果否则语句

if-else语法中,我们可以提供当条件变为 false 时要执行的操作列表。

if-else语句的语法如下 -

句法

if (condition)
   action-1
else
   action-2

在上面的语法中,当条件评估为 true 时执行 action-1,当条件评估为 false 时执行 action-2。例如,以下示例检查数字是否为偶数 -

例子

[jerry]$ awk 'BEGIN {
   num = 11; if (num % 2 == 0) printf "%d is even number.\n", num; 
      else printf "%d is odd number.\n", num 
}'

执行此代码时,您将得到以下结果 -

输出

11 is odd number.

如果-否则-如果阶梯

我们可以通过使用多个if -else 语句轻松创建if-else-if梯形图。以下示例演示了这一点 -

例子

[jerry]$ awk 'BEGIN {
   a = 30;
   
   if (a==10)
   print "a = 10";
   else if (a == 20)
   print "a = 20";
   else if (a == 30)
   print "a = 30";
}'

执行此代码时,您将得到以下结果 -

输出

a = 30

AWK - 循环

本章通过适当的示例解释了 AWK 的循环。循环用于以重复的方式执行一组操作。只要循环条件为真,循环就会继续执行。

For循环

for循环的语法是 -

句法

for (initialization; condition; increment/decrement)
   action

最初,for语句执行初始化操作,然后检查条件。如果条件为真,则执行操作,然后执行递增或递减操作。只要条件为真,循环就会继续执行。例如,以下示例使用for循环打印 1 到 5 -

例子

[jerry]$ awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }'

执行此代码时,您将得到以下结果 -

输出

1
2
3
4
5

While 循环

while循环不断执行操作,直到特定的逻辑条件计算为 true 这是while循环的语法-

句法

while (condition)
   action

AWK首先检查条件;如果条件为真,则执行该操作。只要循环条件计算结果为 true,就会重复此过程。例如,以下示例使用while循环打印 1 到 5 -

例子

[jerry]$ awk 'BEGIN {i = 1; while (i < 6) { print i; ++i } }'

执行此代码时,您将得到以下结果 -

输出

1
2
3
4
5

Do-While 循环

do -while循环与 while 循环类似,不同之处在于测试条件是在循环末尾评估的。这是do-while循环的语法-

句法

do
   action
while (condition)

do-while循环中,即使条件语句的计算结果为 false,操作语句也至少执行一次。例如,以下示例使用do-while循环打印 1 到 5 个数字 -

例子

[jerry]$ awk 'BEGIN {i = 1; do { print i; ++i } while (i < 6) }'

执行此代码时,您将得到以下结果 -

输出

1
2
3
4
5

中断声明

顾名思义,它用于结束循环执行。下面是一个当总和大于 50 时结束循环的示例。

例子

[jerry]$ awk 'BEGIN {
   sum = 0; for (i = 0; i < 20; ++i) { 
      sum += i; if (sum > 50) break; else print "Sum =", sum 
   } 
}'

执行此代码时,您将得到以下结果 -

输出

Sum = 0
Sum = 1
Sum = 3
Sum = 6
Sum = 10
Sum = 15
Sum = 21
Sum = 28
Sum = 36
Sum = 45

继续声明

continue语句在循环内使用以跳到循环的下一次迭代。当您希望跳过循环内某些数据的处理时,它非常有用。例如,以下示例使用continue语句打印 1 到 20 之间的偶数。

例子

[jerry]$ awk 'BEGIN {
   for (i = 1; i <= 20; ++i) {
      if (i % 2 == 0) print i ; else continue
   } 
}'

执行此代码时,您将得到以下结果 -

输出

2
4
6
8
10
12
14
16
18
20

退出声明

它用于停止脚本的执行。它接受一个整数作为参数,它是 AWK 进程的退出状态代码。如果未提供参数,退出将返回状态零。下面是当总和大于 50 时停止执行的示例。

例子

[jerry]$ awk 'BEGIN {
   sum = 0; for (i = 0; i < 20; ++i) {
      sum += i; if (sum > 50) exit(10); else print "Sum =", sum 
   } 
}'

输出

执行此代码时,您将得到以下结果 -

Sum = 0
Sum = 1
Sum = 3
Sum = 6
Sum = 10
Sum = 15
Sum = 21
Sum = 28
Sum = 36
Sum = 45

让我们检查脚本的返回状态。

例子

[jerry]$ echo $?

执行此代码时,您将得到以下结果 -

输出

10

AWK - 内置函数

AWK 内置了许多可供程序员随时使用的函数。本章通过适当的示例描述算术、字符串、时间、位操作和其他杂项函数。

编号 内置功能及说明
1 算术函数

AWK 具有以下内置算术函数。

2 字符串函数

AWK 具有以下内置字符串函数。

3 时间函数

AWK 具有以下内置时间函数。

4 位操作函数

AWK 具有以下内置位操作函数。

5 杂项功能

AWK 具有以下杂项功能。

AWK - 用户定义函数

函数是程序的基本构建块。AWK 允许我们定义自己的函数。一个大程序可以分为多个函数,每个函数可以独立编写/测试。它提供了代码的可重用性。

下面给出的是用户定义函数的一般格式 -

句法

function function_name(argument1, argument2, ...) { 
   function body
}

在此语法中,function_name是用户定义函数的名称。函数名称应以字母开头,其余字符可以是数字、字母字符或下划线的任意组合。AWK 的保留字不能用作函数名。

函数可以接受多个以逗号分隔的参数。参数不是强制性的。您还可以创建不带任何参数的用户定义函数。

函数体由一个或多个 AWK 语句组成。

让我们编写两个函数来计算最小值和最大值,并从另一个名为main的函数调用这些函数。Functions.awk文件包含 -

例子

# Returns minimum number
function find_min(num1, num2){
   if (num1 < num2)
   return num1
   return num2
}
# Returns maximum number
function find_max(num1, num2){
   if (num1 > num2)
   return num1
   return num2
}
# Main function
function main(num1, num2){
   # Find minimum number
   result = find_min(10, 20)
   print "Minimum =", result
  
   # Find maximum number
   result = find_max(10, 20)
   print "Maximum =", result
}
# Script execution starts here
BEGIN {
   main(10, 20)
}

执行此代码时,您将得到以下结果 -

输出

Minimum = 10
Maximum = 20

AWK - 输出重定向

到目前为止,我们在标准输出流上显示了数据。我们还可以将数据重定向到文件。重定向出现在printprintf语句之后。AWK 中的重定向的编写方式与 shell 命令中的重定向类似,只不过它们是在 AWK 程序内部编写的。本章通过适当的示例解释了重定向。

重定向运算符

重定向运算符的语法是 -

句法

print DATA > output-file

它将数据写入输出文件。如果输出文件不存在,则会创建一个。当使用这种类型的重定向时,在将第一个输出写入输出文件之前,输出文件将被删除。对同一输出文件的后续写入操作不会删除输出文件,而是附加到它。例如,下面的例子写Hello, World !!! 到文件。

让我们创建一个包含一些文本数据的文件。

例子

[jerry]$ echo "Old data" > /tmp/message.txt
[jerry]$ cat /tmp/message.txt

执行此代码时,您将得到以下结果 -

输出

Old data

现在让我们使用 AWK 的重定向运算符将一些内容重定向到其中。

例子

[jerry]$ awk 'BEGIN { print "Hello, World !!!" > "/tmp/message.txt" }'
[jerry]$ cat /tmp/message.txt

执行此代码时,您将得到以下结果 -

输出

Hello, World !!!

追加运算符

附加运算符的语法如下 -

句法

print DATA >> output-file

它将数据附加到输出文件中。如果输出文件不存在,则会创建一个。使用这种类型的重定向时,新内容将附加在文件末尾。例如,以下示例附加Hello, World !!! 到文件。

让我们创建一个包含一些文本数据的文件。

例子

[jerry]$ echo "Old data" > /tmp/message.txt 
[jerry]$ cat /tmp/message.txt

执行此代码时,您将得到以下结果 -

输出

Old data

现在让我们使用 AWK 的附加运算符向其附加一些内容。

例子

[jerry]$ awk 'BEGIN { print "Hello, World !!!" >> "/tmp/message.txt" }'
[jerry]$ cat /tmp/message.txt

执行此代码时,您将得到以下结果 -

输出

Old data
Hello, World !!!

管道

可以通过管道而不是使用文件将输出发送到另一个程序。此重定向打开一个命令管道,并通过该管道将项目的值写入另一个进程以执行该命令。重定向参数命令实际上是一个 AWK 表达式。这是管道的语法 -

句法

print items | command

让我们使用tr命令将小写字母转换为大写字母。

例子

[jerry]$ awk 'BEGIN { print "hello, world !!!" | "tr [a-z] [A-Z]" }'

执行此代码时,您将得到以下结果 -

输出

HELLO, WORLD !!!

双向通讯

AWK 可以使用|& 与外部进程进行通信,这是双向通信。例如,下面的示例使用tr命令将小写字母转换为大写字母。我们的command.awk文件包含 -

例子

BEGIN {
   cmd = "tr [a-z] [A-Z]"
   print "hello, world !!!" |& cmd
   close(cmd, "to")
   
   cmd |& getline out
   print out;
   close(cmd);
}

执行此代码时,您将得到以下结果 -

输出

HELLO, WORLD !!!

剧本看起来很神秘吗?让我们揭开它的神秘面纱。

  • 第一条语句cmd = "tr [az] [AZ]"是我们与 AWK 建立双向通信的命令。

  • 下一条语句,即 print 命令,为tr命令提供输入。这里&| 表示双向通信。

  • 第三条语句,即close(cmd, "to") ,在竞争执行后关闭to进程。

  • 下一条语句cmd |& getline out借助 getline 函数将输出存储到 out 变量中。

  • 下一个 print 语句打印输出,最后close函数关闭命令。

AWK - 漂亮的打印

到目前为止,我们已经使用 AWK 的printprintf函数在标准输出上显示数据。但 printf 比我们之前看到的要强大得多。该函数借用自 C 语言,在生成格式化输出时非常有用。以下是 printf 语句的语法 -

句法

printf fmt, expr-list

在上面的语法中,fmt是一个格式规范和常量的字符串。expr-list是与格式说明符对应的参数列表。

转义序列

与任何字符串类似,格式可以包含嵌入的转义序列。下面讨论的是 AWK 支持的转义序列 -

新队

以下示例使用换行符在单独的行中打印HelloWorld -

例子

[jerry]$ awk 'BEGIN { printf "Hello\nWorld\n" }'

执行此代码时,您将得到以下结果 -

输出

Hello
World

水平制表符

以下示例使用水平选项卡来显示不同的字段 -

例子

[jerry]$ awk 'BEGIN { printf "Sr No\tName\tSub\tMarks\n" }'

执行上面的代码,你会得到以下结果 -

输出

Sr No   Name    Sub Marks

垂直制表符

以下示例在每个字段后使用垂直制表符 -

例子

[jerry]$ awk 'BEGIN { printf "Sr No\vName\vSub\vMarks\n" }'

执行此代码时,您将得到以下结果 -

输出

Sr No
   Name
      Sub
         Marks

退格键

以下示例在除最后一个字段之外的每个字段后打印一个退格键。它会删除前三个字段中的最后一个数字。例如,Field 1显示为Field,因为最后一个字符被退格键删除。但是,最后一个字段Field 4按原样显示,因为Field 4之后没有\b

例子

[jerry]$ awk 'BEGIN { printf "Field 1\bField 2\bField 3\bField 4\n" }'

执行此代码时,您将得到以下结果 -

输出

Field Field Field Field 4

回车

在下面的示例中,打印每个字段后,我们执行回车并在当前打印值之上打印下一个值。这意味着,在最终输出中,您只能看到Field 4,因为它是在所有先前字段之上打印的最后一个内容。

例子

[jerry]$ awk 'BEGIN { printf "Field 1\rField 2\rField 3\rField 4\n" }'

执行此代码时,您将得到以下结果 -

输出

Field 4

换页

以下示例在打印每个字段后使用换页符。

例子

[jerry]$ awk 'BEGIN { printf "Sr No\fName\fSub\fMarks\n" }'

执行此代码时,您将得到以下结果 -

输出

Sr No
   Name
      Sub
         Marks

格式说明符

与 C 语言一样,AWK 也有格式说明符。AWK 版本的 printf 语句接受以下转换规范格式 -

%C

它打印一个字符。如果用于%c 的参数是数字,则将其视为字符并打印。否则,假定参数是字符串,并且打印该字符串的唯一第一个字符。

例子

[jerry]$ awk 'BEGIN { printf "ASCII value 65 = character %c\n", 65 }'

输出

执行此代码时,您将得到以下结果 -

ASCII value 65 = character A

%d 和 %i

它仅打印小数的整数部分。

例子

[jerry]$ awk 'BEGIN { printf "Percentags = %d\n", 80.66 }'

执行此代码时,您将得到以下结果 -

输出

Percentags = 80

%e 和 %E

它打印 [-]d.dddddde[+-]dd 形式的浮点数。

例子

[jerry]$ awk 'BEGIN { printf "Percentags = %E\n", 80.66 }'

执行此代码时,您将得到以下结果 -

输出

Percentags = 8.066000e+01

% E格式使用E而不是 e。

例子

[jerry]$ awk 'BEGIN { printf "Percentags = %e\n", 80.66 }'

执行此代码时,您将得到以下结果 -

输出

Percentags = 8.066000E+01

%F

它打印 [-]ddd.dddddd 形式的浮点数。

例子

[jerry]$ awk 'BEGIN { printf "Percentags = %f\n", 80.66 }'

执行此代码时,您将得到以下结果 -

输出

Percentags = 80.660000

%g 和 %G

使用 %e 或 %f 转换(以较短者为准),并抑制非有效零。

例子

[jerry]$ awk 'BEGIN { printf "Percentags = %g\n", 80.66 }'

输出

执行此代码时,您将得到以下结果 -

Percentags = 80.66

%G格式使用%E而不是 %e。

例子

[jerry]$ awk 'BEGIN { printf "Percentags = %G\n", 80.66 }'

执行此代码时,您将得到以下结果 -

输出

Percentags = 80.66

%o

它打印一个无符号的八进制数。

例子

[jerry]$ awk 'BEGIN { printf "Octal representation of decimal number 10 = %o\n", 10}'

执行此代码时,您将得到以下结果 -

输出

Octal representation of decimal number 10 = 12

%u

它打印一个无符号的十进制数。

例子

[jerry]$ awk 'BEGIN { printf "Unsigned 10 = %u\n", 10 }'

执行此代码时,您将得到以下结果 -

输出

Unsigned 10 = 10

%s

它打印一个字符串。

例子

[jerry]$ awk 'BEGIN { printf "Name = %s\n", "Sherlock Holmes" }'

执行此代码时,您将得到以下结果 -

输出

Name = Sherlock Holmes

%x 和 %X

它打印一个无符号的十六进制数。% X格式使用大写字母而不是小写字母。

例子

[jerry]$ awk 'BEGIN { 
   printf "Hexadecimal representation of decimal number 15 = %x\n", 15
}'

执行此代码时,您将得到以下结果 -

输出

Hexadecimal representation of decimal number 15 = f

现在让我们使用 %X 并观察结果 -

例子

[jerry]$ awk 'BEGIN { 
   printf "Hexadecimal representation of decimal number 15 = %X\n", 15
}'

执行此代码时,您将得到以下结果 -

输出

Hexadecimal representation of decimal number 15 = F

%%

它打印单个%字符并且不转换任何参数。

例子

[jerry]$ awk 'BEGIN { printf "Percentags = %d%%\n", 80.66 }'

执行此代码时,您将得到以下结果 -

输出

Percentags = 80%

带 % 的可选参数

对于%,我们可以使用以下可选参数 -

宽度

该字段被填充到宽度。默认情况下,该字段用空格填充,但当使用 0 标志时,它用零填充。

例子

[jerry]$ awk 'BEGIN { 
   num1 = 10; num2 = 20; printf "Num1 = %10d\nNum2 = %10d\n", num1, num2 
}'

执行此代码时,您将得到以下结果 -

输出

Num1 =         10
Num2 =         20

前导零

前导零充当标志,表示输出应该用零而不是空格填充。请注意,此标志仅在字段比要打印的值宽时才有效。下面的例子描述了这一点 -

例子

[jerry]$ awk 'BEGIN { 
   num1 = -10; num2 = 20; printf "Num1 = %05d\nNum2 = %05d\n", num1, num2 
}'

执行此代码时,您将得到以下结果 -

输出