当前位置: 首页 > 科技观察

通过两个简单的教程提高您的awk技能

时间:2023-03-20 13:42:49 科技观察

超越单行awk脚本,学习如何进行邮件合并和字数统计。awk是Unix和Linux用户工具箱中最古老的工具之一。awk由AlfredAho、PeterWeinberger和BrianKernighan(工具名称中的A、W和K)在1970年代创建,用于复杂的文本流处理。它是流编辑器sed的配套工具,专为逐行处理文本文件而设计。awk支持更复杂的结构化程序,是一门完整的编程语言。本文介绍如何使用awk完成结构化程度更高、更复杂的任务,包括一个简单的邮件合并程序。awk的程序结构awk脚本由{}(大括号)包围的功能块组成,其中有两个特殊的功能块BEGIN和END,分别在处理第一行输入流之前和处理最后一行之后执行线。在这两者之间,块的形式为:pattern{actionstatement}当输入缓冲区中的一行与模式匹配时,每个块都会被执行。如果不包含模式,则在输入流的每一行上执行功能块。此外,可以在awk中使用以下语法来定义可以从任何块调用的函数。functionfunctionname(parameterlist){statement}这种模式匹配块和函数的组合允许开发人员构建awk程序以实现重用和可读性。awk如何处理文本流awk从输入文件或流中一次读取一行文本,并使用字段分隔符将其解析为字段。在awk术语中,当前缓冲区是一条记录。有一些特殊变量会影响awk读取和处理文件的方式:FS(字段分隔符)。默认情况下,这是任何空白字符(空格或制表符)。RS(记录分隔符记录分隔符)。默认情况下它是一个换行符(n)。NF(字段数)。当awk解析一行时,这个变量被设置为解析的字段数。$0:当前记录。$1、$2、$3等:当前记录的第一、第二、第三等字段。NR(记录数)。到目前为止,awk脚本已解析的记录数。还有更多的变量会影响awk的行为,但知道这些就足以开始了。单行awk脚本对于这样一个强大的工具,有趣的是awk的大多数使用都是基本的单行。也许最常见的awk程序是打印CSV文件、日志文件等输入行中的选定字段。例如,以下单行打印来自/etc/passwd的用户名列表:awk-F":"'{print$1}'/etc/passwd如上所述,$1是当前记录中的第一个字段。-F选项将FS变量设置为字符:。字段分隔符也可以在BEGIN功能块中设置:awk'BEGIN{FS=":"}{print$1}'/etc/passwd在下面的例子中,每个shell不是/sbin/nologin的用户都可以通过Preface此块具有要打印的匹配模式:awk'BEGIN{FS=":"}!/\/sbin\/nologin/{print$1}'/etc/passwdawk高级:邮件合并现在你已经有了一些基础知识,试着通过一个更结构化的例子来深入理解awk:创建邮件合并。邮件合并使用两个文件,其中一个(在此示例中称为email_template.txt)包含您要发送的电子邮件的模板:From:ProgramcommitteeTo:{firstname}{lastname}<{电子邮件}>主题:您的演示提案亲爱的{firstname},感谢您的演示提案:{title}我们很高兴地通知您,您的提案已成功!我们将尽快与您联系,提供有关活动日程的更多信息。谢谢您,计划委员会,另一个是CSV文件(名为proposals.csv),其中包含您要通过电子邮件发送的人:名字、姓氏、电子邮件、职位Harry、Potter,hpotter@hogwarts.edu,"通过3个简单的步骤击败你的敌人"Jack,Reacher,reacher@covert.mil,"初学者的肉搏战"Mickey,Mouse,mmouse@disney.com,"幸存的公开演讲用吱吱嘎嘎的声音“Santa,Claus,sclaus@northpole.org,”高效列表制作“你读取CSV文件,替换第一个文件中的相关字段(跳过第一行),然后将结果写入文件名为acceptanceN.txt,每次解析一行文件名中的N递增。在名为mail_merge.awk的文件中编写awk程序。awk脚本中的语句由;分隔。第一项任务是设置字段分隔符变量和脚本所需的其他几个变量。您还需要读取并丢弃CSV中的第一行,否则将创建一个以亲爱的名字开头的文件。为此,使用特殊函数getline并在读取后将记录计数器重置为0。开始{FS=",";template="email_template.txt";输出=“接受”;获取线路;NR=0;}主要功能非常简单:每次处理一行时,都会为各种字段设置一个变量——名字、姓氏、电子邮件和职务。模板文件逐行读取,函数sub用于用关联变量的值替换任何出现的特殊字符序列。然后将该行连同所做的任何替换一起输出到输出文件。由于每一行都处理模板文件和不同的输出文件,因此在处理下一条记录之前,需要清理并关闭这些文件的文件句柄。{#从输入文件中读取关联字段firstname=$1;姓氏=$2;电子邮件=$3;标题=$4;#设置输出文件名outfile=(outputNR".txt");#从模板中读取一行,将特定字段替换为#并将结果打印到输出文件。while((getlineln0){sub(/{firstname}/,firstname,ln);sub(/{lastname}/,lastname,ln);sub(/{email}/,email,ln);sub(/{title}/,title,ln);打印(ln)>输出文件;}#关闭模板和输出文件,继续下一条记录close(outfile);关闭(模板);}你已经完成了!在命令行上运行脚本:awk-fmail_merge.awkproposals.csv或awk-fmail_merge.awk{}@!\"'\t]+";}接下来,主循环函数遍历每个字段,忽略任何空字段(如果行尾有标点符号,就会发生这种情况),并且增加行中的单词数:{for(i=1;i<=NF;i++){if($i!=""){words[$i]++;}}}最后,处理完文本,使用END函数打印数组的内容,然后使用awk的能力将输出通过管道传输到shell命令,对数字进行排序,并打印出出现频率最高的20个单词。END{sort_head="sort-k2-nr|head-n20";for(wordinwords){printf"%s\t%d\n",word,words[word]|}排序头;}close(sort_head);}在本文的早期草稿上运行此脚本会产生以下输出:[dneary@dhcp-49-32.bos.redhat.com]$awk-fwordcount.awk