帮助你排序文本文件的 Awk 命令行或脚本(推荐)
Awk是一个强大的工具,可以执行某些可能由其它常见实用程序(包括sort)来完成的任务。
Awk是个普遍存在的Unix命令,用于扫描和处理包含可预测模式的文本。但是,由于它具有函数功能,因此也可以合理地称之为编程语言。
令人困惑的是,有不止一个awk。(或者,如果你认为只有一个,那么其它几个就是克隆。)有awk(由Aho、Weinberger和Kernighan编写的原始程序),然后有nawk、mawk和GNU版本的gawk。GNU版本的awk是该实用程序的一个高度可移植的自由软件版本,具有几个独特的功能,因此本文是关于GNUawk的。
虽然它的正式名称是gawk,但在GNU+Linux系统上,它的别名是awk,并用作该命令的默认版本。在其他没有带有GNUawk的系统上,你必须先安装它并将其称为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;LittleBlue Spheniscus;demersus;Brisson;1760;African Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed Eudyptes;chrysocome;Viellot;1816;SothernRockhopper Torvaldis;linux;Ewing,L;1996;Tux
这是一个很小的数据集,但它提供了多种数据类型:
- 属名和种名,彼此相关但又是分开的
- 姓,有时是以逗号开头的首字母缩写
- 代表日期的整数
- 任意术语
- 所有字段均以分号分隔
根据你的教育背景,你可能会认为这是二维数组或表格,或者只是行分隔的数据集合。你如何看待它只是你的问题,而awk只认识文本。由你决定告诉awk你想如何解析它。
只想排序
如果你只想按特定的可定义字段(例如电子表格中的“单元格”)对文本数据集进行排序,则可以使用sort命令。
字段和记录
无论输入的格式如何,都必须在其中找到模式才可以专注于对你重要的数据部分。在此示例中,数据由两个因素定界:行和字段。每行都代表一个新的记录,就如你在电子表格或数据库转储中看到的一样。在每一行中,都有用分号(;)分隔的不同的字段(将其视为电子表格中的单元格)。
awk一次只处理一条记录,因此,当你在构造发给awk的这指令时,你可以只关注一行记录。写下你想对一行数据执行的操作,然后在下一行进行测试(无论是心理上还是用awk进行测试),然后再进行其它的一些测试。最后,你要对你的awk脚本要处理的数据做好假设,以便可以按你要的数据结构提供给你数据。
在这个例子中,很容易看到每个字段都用分号隔开。为简单起见,假设你要按每行的第一字段对列表进行排序。
在进行排序之前,你必须能够让awk只关注在每行的第一个字段上,因此这是第一步。终端中awk命令的语法为awk,后跟相关选项,最后是要处理的数据文件。
$awk--field-separator=";"'{print$1;}'penguins.list Aptenodytes Pygoscelis Eudyptula Spheniscus Megadyptes Eudyptes Torvaldis
因为字段分隔符是对Bashshell具有特殊含义的字符,所以必须将分号括在引号中或在其前面加上反斜杠。此命令仅用于证明你可以专注于特定字段。你可以使用另一个字段的编号尝试相同的命令,以查看数据的另一个“列”的内容:
$awk--field-separator=";"'{print$3;}'penguins.list Miller,JF Wagler Bonaparte Brisson Milne-Edwards Viellot Ewing,L
我们尚未进行任何排序,但这是良好的基础。
脚本编程
awk不仅仅是命令,它是一种具有索引、数组和函数的编程语言。这很重要,因为这意味着你可以获取要排序的字段列表,将列表存储在内存中,进行处理,然后打印结果数据。对于诸如此类的一系列复杂操作,在文本文件中进行操作会更容易,因此请创建一个名为sort.awk的新文件并输入以下文本:
#!/bin/gawk-f BEGIN{ FS=";"; }
这会将该文件建立为awk脚本,该脚本中包含执行的行。
BEGIN语句是awk提供的特殊设置功能,用于只需要执行一次的任务。定义内置变量FS,它代表字段分隔符fieldseparator,并且与你在awk命令中使用--field-separator设置的值相同,它只需执行一次,因此它包含在BEGIN语句中。
awk中的数组
你已经知道如何通过使用$符号和字段编号来收集特定字段的值,但是在这种情况下,你需要将其存储在数组中而不是将其打印到终端。这是通过awk数组完成的。awk数组的重要之处在于它包含键和值。想象一下有关本文的内容;它看起来像这样:author:"seth",title:"Howtosortwithawk",length:1200。诸如作者、标题和长度之类的元素是键,跟着的内容为值。
在排序的上下文中这样做的好处是,你可以将任何字段分配为键,将任何记录分配为值,然后使用内置的awk函数asorti()(按索引排序)按键进行排序。现在,随便假设你只想按第二个字段排序。
没有被特殊关键字BEGIN或END引起来的awk语句是在每个记录都要执行的循环。这是脚本的一部分,该脚本扫描数据中的模式并进行相应的处理。每次awk将注意力转移到一条记录上时,都会执行{}中的语句(除非以BEGIN或END开头)。
要将键和值添加到数组,请创建一个包含数组的变量(在本示例脚本中,我将其称为ARRAY,虽然不是很原汁原味,但很清楚),然后在方括号中分配给它键,用等号(=)连接值。
{#dumpeachfieldintoanarray ARRAY[$2]=$R; }
在此语句中,第二个字段的内容($2)用作关键字,而当前记录($R)用作值。
asorti()函数
除了数组之外,awk还具有一些基本函数,你可以将它们用作常见任务的快速简便的解决方案。GNUawk中引入的函数之一asorti()提供了按键(索引)或值对数组进行排序的功能。
你只能在对数组进行填充后对其进行排序,这意味着此操作不能对每个新记录都触发,而只能在脚本的最后阶段进行。为此,awk提供了特殊的END关键字。与BEGIN相反,END语句仅在扫描了所有记录之后才触发一次。
将这些添加到你的脚本:
END{ asorti(ARRAY,SARRAY); #getlength j=length(SARRAY); for(i=1;i<=j;i++){ printf("%s%s\n",SARRAY[i],ARRAY[SARRAY[i]]) } }
asorti()函数获取ARRAY的内容,按索引对其进行排序,然后将结果放入名为SARRAY的新数组(我在本文中发明的任意名称,表示“排序的ARRAY”)。
接下来,将变量j(另一个任意名称)分配给length()函数的结果,该函数计算SARRAY中的项数。
最后,使用for循环使用printf()函数遍历SARRAY中的每一项,以打印每个键,然后在ARRAY中打印该键的相应值。
运行该脚本
要运行你的awk脚本,先使其可执行:
$chmod+xsorter.awk
然后针对penguin.list示例数据运行它:
$./sorter.awkpenguins.list antipodesMegadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed chrysocomeEudyptes;chrysocome;Viellot;1816;SothernRockhopper demersusSpheniscus;demersus;Brisson;1760;African forsteriAptenodytes;forsteri;Miller,JF;1778;Emperor linuxTorvaldis;linux;Ewing,L;1996;Tux minorEudyptula;minor;Bonaparte;1867;LittleBlue papuaPygoscelis;papua;Wagler;1832;Gentoo
如你所见,数据按第二个字段排序。
这有点限制。最好可以在运行时灵活选择要用作排序键的字段,以便可以在任何数据集上使用此脚本并获得有意义的结果。
添加命令选项
你可以通过在脚本中使用字面值var将命令变量添加到awk脚本中。更改脚本,以使迭代子句在创建数组时使用var:
{#dumpeachfieldintoanarray ARRAY[$var]=$R; }
尝试运行该脚本,以便在执行脚本时使用-vvar选项将其按第三字段排序:
$./sorter.awk-vvar=3penguins.list BonaparteEudyptula;minor;Bonaparte;1867;LittleBlue BrissonSpheniscus;demersus;Brisson;1760;African Ewing,LTorvaldis;linux;Ewing,L;1996;Tux Miller,JFAptenodytes;forsteri;Miller,JF;1778;Emperor Milne-EdwardsMegadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed ViellotEudyptes;chrysocome;Viellot;1816;SothernRockhopper WaglerPygoscelis;papua;Wagler;1832;Gentoo
修正
本文演示了如何在纯GNUawk中对数据进行排序。你可以对脚本进行改进,以便对你有用,花一些时间在gawk的手册页上研究awk函数并自定义脚本以获得更好的输出。
这是到目前为止的完整脚本:
#!/usr/bin/awk-f #GPLv3appearshere #usage:./sorter.awk-vvar=NUMFILE BEGIN{FS=";";} {#dumpeachfieldintoanarray ARRAY[$var]=$R; } END{ asorti(ARRAY,SARRAY); #getlength j=length(SARRAY); for(i=1;i<=j;i++){ printf("%s%s\n",SARRAY[i],ARRAY[SARRAY[i]]) } }
总结
以上所述是小编给大家介绍的帮助你排序文本文件的Awk命令行或脚本,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。