awk 脚本
Awk是普遍存在的Unix命令,用于扫描和处理包含可预测模式的文本。 但是,由于它具有功能,因此也有理由将其称为编程语言。
令人困惑的是,awk有多个。 (或者,如果您认为只有一个,那么就会有几个克隆。)有awk ,它是Aho,Weinberger和Kernighan编写的原始程序,然后是nawk , mawk和GNU版本gawk 。 GNU版本的awk是该实用程序的高度可移植的免费软件版本,具有几个独特的功能,因此本文是关于GNU awk的。
虽然它的正式名称是gawk,但在GNU + Linux系统上,它的别名是awk,并用作该命令的默认版本。 在其他不随GNU awk一起提供的系统上,您必须安装它并将其称为gawk,而不是awk。 本文互换使用术语awk和gawk。
作为命令和编程语言,awk成为了强大的工具,可用于执行可能会被排序 , 剪切 , 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除了文本外没有其他期望。 由您决定告诉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数组完成的。 awk数组的重要之处在于它包含键和值。 想象一下有关本文的内容; 它看起来像这样: author:“ seth”,title:“如何用awk排序”,长度:1200 。 诸如作者 , 标题和长度之类的元素是键,以下内容为值。
在排序的上下文中,这样做的好处是可以将任何字段分配为键,将任何记录分配为值,然后使用内置的awk函数asorti() (按索引排序)按键进行排序。 现在,假定任意你只需要通过第二个字段进行排序。
没有特殊关键字BEGIN或END开头的Awk语句是在每个记录处发生的循环。 这是脚本的一部分,该脚本扫描数据中的模式并进行相应的处理。 每当awk将注意力转移到一条记录时,都会执行{}中的语句(除非后面带有BEGIN或END )。
要将键和值添加到数组,请创建一个包含数组的变量(在本示例脚本中,我将其称为ARRAY ,它并不是很原始,但非常清晰),然后在方括号中将键和值赋给它等号( = )。
{
# dump each field into an array
ARRAY
[
$2
] =
$R ;
}
在此语句中,第二个字段( $ 2 )的内容用作关键字,而当前记录( $ R )用作值。
asorti()函数
除了数组,awk还具有一些基本功能,您可以将它们用作常见任务的快速简便的解决方案。 GNU awk中引入的功能之一asorti()提供了按键(或index )或值对数组进行排序的功能。
您只能在对数组进行填充后对其进行排序,这意味着此操作不能对每个新记录都发生,而只能对脚本的最后阶段进行。 为此,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的新数组中(我在本文中发明的任意名称,即Sorted ARRAY )。
接下来,为变量j (另一个任意名称)分配给length()函数的结果,该函数计算SARRAY中的项数 。
最后,使用for循环使用printf()函数遍历SARRAY中的每个项以打印每个键,然后打印该键在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
]
]
)
}
}
awk 脚本