Awk是一种Unix命令,用于扫描和处理包含可预测模式的文本。然而,因为它具有函数功能,所以它也被称为编程语言。
奇怪的是,awk其实是有很多种。(或者,如果你相信只能有一种,那么就有很多种它的克隆。)其中,最初的有awk,他是由Aho,Weinberger和Kernighan编写的程序,还有nawk,mawk,和GNU版本gawk。GNU版本的awk是该实用程序的高度可移植的免费软件版本,具有几个独特的功能,因此本文是关于GNUawk的。
虽然它的正式名称是gawk,但在gnu+linux系统中,它的别名是awk,并且是该命令的默认版本。在其他没有搭载GNU awk的系统上,您必须安装它并将其称为gawk,而不是awk。本文将交替使用awk和gawk这两个术语。
作为命令和编程语言,awk成为了强大的工具,可以处理那些可能会被sort,cut,uniq和其他常见实用程序使用的任务。幸运的是,开放源代码中有很多冗余空间,因此,如果您面临是否使用awk的问题,答案应该是“也不错”。
Awk的灵活性之处在于,如果您已经确定使用awk来处理任务,那么无论前进的道路上出现什么情况,您都可以继续使用awk。这包括对数据进行排序的永恒需求,而不是将数据交付给您的顺序。
在探索 awk 的排序方法之前,先生成一个样本数据集来使用。为了你就不会被边缘案例和意想不到的复杂性分散注意力,我们需要它保持简单。这是本文使用的示例集:
Aptenodytes;forsteri;Miller,JF;1778;Emperor
Pygoscelis;papua;Wagler;1832;Gentoo
Eudyptula;minor;Bonaparte;1867;Little Blue
Spheniscus;demersus;Brisson;1760;African
Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
Torvaldis;linux;Ewing,L;1996;Tux
这是一个很小的数据集,但是它提供了各种各样的数据类型:
根据您的知识您可以将其视为一个2D 数组或表,或者仅仅是一个以行分隔的数据集合。 如何看待它取决于你自己,因为awk只会处理文本,需要由您指定如何解析它。
如果您只想按特定的,可定义的字段(例如电子表格中的“单元格”)对文本数据集进行排序,则可以使用sort命令 。
无论输入数据的格式如何,您都必须在其中找到一种模式,以便能够专注于最重要的数据部分。在本例中,数据由两种分隔: 行和字段。 每一行代表一条新记录,就像您在电子表格或数据库转储中可能看到的那样。 在每一行中,都有不同的字段(可以将它们看作电子表格中的单元格) ,这些字段之间用分号分隔(;)。
Awk 一次处理一条记录,因此当您构建将要给 Awk 的指令时,您可以只关注一行。 用一行建立你想要做的事情,然后在下一行或者更多行测试它(无论是心理上还是用awk进行测试)。 最后,您将得到一个很好的假设,即 awk 脚本必须执行哪些操作才能为您提供所需的数据结构。
在这种情况下,很容易看出每个字段都由分号分隔。 为了简单起见,假设您希望根据每行的第一个字段对列表进行排序。
在进行排序之前,必须能够将 awk 集中在每行的第一个字段上,因此这是第一步。 终端中awk命令的语法为awk ,后跟相关选项,然后是awk命令,最后是要处理的数据文件。
$ awk --field-separator=";" '{print $1;}' penguins.list
Aptenodytes
Pygoscelis
Eudyptula
Spheniscus
Megadyptes
Eudyptes
Torvaldis
因为字段分隔符是对 Bash shell 具有特殊意义的字符,所以必须将分号包含在引号中,或者在前面加上反斜杠。 这个命令仅用于证明您可以关注特定的字段。 你可以使用另一个字段的编号来查看你的数据的另一个“列”的内容:
$ awk --field-separator=";" '{print $3;}' penguins.list
Miller,JF
Wagler
Bonaparte
Brisson
Milne-Edwards
Viellot
Ewing,L
目前还没有任何排序结果,但这是很好的基础工作。
Awk 不仅仅是一个命令; 它是一种编程语言,具有索引、数组和函数。 这一点很重要,因为它意味着您可以获取一个要进行排序的字段列表,将该列表存储在内存中,对其进行处理,然后输出结果数据。对于诸如此类的一系列复杂操作,在文本文件中进行操作会更容易,因此请创建一个名为sorter.awk的新文件并输入以下文本:
#!/usr/bin/awk -f
BEGIN {
FS=";";
}
这会将文件建立为awk脚本,该脚本执行文件中包含的行。
BEGIN语句是awk提供的特殊设置功能,用于只需要执行一次的任务。 定义内置变量FS ,它表示字段分隔符,并且与在--field-separator中的awk命令中设置的值相同,只需执行一次,因此它包含在BEGIN语句中。
您已经知道如何通过使用 $符号和字段号收集特定字段的值,但是在这种情况下,您需要将其存储在数组中,而不是将其打印到终端。 这是通过 awk 数组完成的。 Awk 数组的重要之处在于它包含键和值。 想象一下这篇文章的数组; 它看起来像这样: author: “seth” ,title:”How to sort with awk”,length: 1200。 像 author、 title 和 length 这样的元素是键,下面的内容是值。
在排序的上下文中,这样做可以将任何字段分配为键,将任何记录分配为值,然后使用内置的awk函数asorti()(按索引排序)按键值进行排序。现在,假设您只希望按第二个字段进行排序。
前面没有特殊关键字BEGIN或END的Awk语句是发生在每个记录上的循环。这是脚本的一部分,它扫描数据中的模式并相应地处理它。每次awk将注意力转向一个记录时,都会执行{}中的语句,除非前面是BEGIN或END。
为了向数组添加键和值,创建一个包含数组的变量(在这个示例脚本中,我称之为 ARRAY,它并不是非常原始,但非常利于理解),然后在方括号中将其分配给键和一个等号。
{ # dump each field into an array
ARRAY[$2] = $R;
}
在这个语句中,第二个字段($2)的内容用作关键词,当前记录($r)用作值。
除了数列之外,awk 还有几个基本函数,您可以将它们用作常见任务的快速简单解决方案。 Gnu awk 中引入的函数之一 asorti ()提供了按键(索引)或值对数组进行排序的能力。
您只能在对数组进行填充后对其进行排序,这意味着该操作不能在每个新记录中发生,而只能在脚本的最后阶段发生。 为此,awk 提供了特殊的 END 关键字。 与 BEGIN 相反,END 语句只在所有记录被扫描之后发生一次。
把这个添加到你的脚本中:
END {
asorti(ARRAY,SARRAY);
# get length
j = length(SARRAY);
for (i = 1; i <= j; i++) {
printf("%s %s\n", SARRAY[i],ARRAY[SARRAY[i]])
}
}
asorti()函数获取ARRAY的内容,根据索引对其进行排序,并将结果放入一个名为SARRAY的新数组中(这是我为本文发明的名称,意为排序数组)。
接下来,为变量j分配length()函数的结果,该函数计算SARRAY中的项数。
最后,使用for循环迭代SARRAY中的每个项,使用printf()函数打印每个键,然后在ARRAY中打印该键的相应值。
运行awk脚本,使其可执行:
$ chmod +x sorter.awk
然后针对penguin.list示例数据运行它:
$ ./sorter.awk penguins.list
antipodes Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
chrysocome Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
demersus Spheniscus;demersus;Brisson;1760;African
forsteri Aptenodytes;forsteri;Miller,JF;1778;Emperor
linux Torvaldis;linux;Ewing,L;1996;Tux
minor Eudyptula;minor;Bonaparte;1867;Little Blue
papua Pygoscelis;papua;Wagler;1832;Gentoo
如您所见,数据将按第二个字段进行排序。
但这有点限制性。 最好能够在运行时灵活地选择要使用哪个字段作为排序键,这样就可以在任何数据集上使用此脚本,并获得有意义的结果。
您可以通过在脚本中使用var将命令变量添加到awk脚本中。 更改脚本,以便在创建数组时迭代子句使用var :
{ # dump each field into an array
ARRAY[$var] = $R;
}
尝试运行脚本,使用-v var选项对第三个字段进行排序:
$ ./sorter.awk -v var=3 penguins.list
Bonaparte Eudyptula;minor;Bonaparte;1867;Little Blue
Brisson Spheniscus;demersus;Brisson;1760;African
Ewing,L Torvaldis;linux;Ewing,L;1996;Tux
Miller,JF Aptenodytes;forsteri;Miller,JF;1778;Emperor
Milne-Edwards Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
Viellot Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
Wagler Pygoscelis;papua;Wagler;1832;Gentoo
本文演示了如何在纯GNU awk中对数据进行排序。 该脚本可以进行改进,因此如果它对您有用,请花一些时间在gawk的手册上研究awk函数并自定义脚本以获得更好的输出。
以下是到目前为止的完整脚本:
#!/usr/bin/awk -f
# GPLv3 appears here
# usage: ./sorter.awk -v var=NUM FILE
BEGIN { FS=";"; }
{ # dump each field into an array
ARRAY[$var] = $R;
}
END {
asorti(ARRAY,SARRAY);
# get length
j = length(SARRAY);
for (i = 1; i <= j; i++) {
printf("%s %s\n", SARRAY[i],ARRAY[SARRAY[i]])
}
}
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。