学习
实践
活动
专区
工具
TVP
写文章
专栏首页用户8870853的专栏通过两个简单的教程来提高你的 awk 技能

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

awk 是 Unix 和 Linux 用户工具箱中最古老的工具之一。awk 由 Alfred Aho、Peter Weinberger 和 Brian Kernighan(即工具名称中的 A、W 和 K)在 20 世纪 70 年代创建,用于复杂的文本流处理。它是流编辑器 sed 的配套工具,后者是为逐行处理文本文件而设计的。awk 支持更复杂的结构化程序,是一门完整的编程语言。

本文将介绍如何使用 awk 完成更多结构化的复杂任务,包括一个简单的邮件合并程序。

awk 的程序结构

awk 脚本是由 {}(大括号)包围的功能块组成,其中有两个特殊的功能块,BEGINEND,它们在处理第一行输入流之前和最后一行处理之后执行。在这两者之间,块的格式为:

模式 { 动作语句 }

当输入缓冲区中的行与模式匹配时,每个块都会执行。如果没有包含模式,则函数块在输入流的每一行都会执行。

另外,以下语法可以用于在 awk 中定义可以从任何块中调用的函数。

function 函数名(参数列表) { 语句 }

这种模式匹配块和函数的组合允许开发者结构化的 awk 程序,以便重用和提高可读性。

awk 如何处理文本流

awk 每次从输入文件或流中一行一行地读取文本,并使用字段分隔符将其解析成若干字段。在 awk 的术语中,当前的缓冲区是一个记录。有一些特殊的变量会影响 awk 读取和处理文件的方式:

  • FS字段分隔符(field separator))。默认情况下,这是任何空格字符(空格或制表符)。
  • RS记录分隔符(record separator))。默认情况下是一个新行(n)。
  • NF字段数(number of fields))。当 awk 解析一行时,这个变量被设置为被解析出字段数。
  • $0: 当前记录。
  • $1$2$3 等:当前记录的第一、第二、第三等字段。
  • NR记录数(number of records))。迄今已被 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 的用户都可以通过在该块前面加上匹配模式来打印出来:

awk 'BEGIN { FS=":" } ! /\/sbin\/nologin/ {print $1 }' /etc/passwd

awk 进阶:邮件合并

现在你已经掌握了一些基础知识,尝试用一个更具有结构化的例子来深入了解 awk:创建邮件合并。

邮件合并使用两个文件,其中一个文件(在本例中称为 email_template.txt)包含了你要发送的电子邮件的模板:

From: Program committee <pc@event.org>
To: {firstname} {lastname} <{email}>
Subject: Your presentation proposal

Dear {firstname},

Thank you for your presentation proposal:
  {title}

We are pleased to inform you that your proposal has been successful! We
will contact you shortly with further information about the event
schedule.

Thank you,
The Program Committee

而另一个则是一个 CSV 文件(名为 proposals.csv),里面有你要发送邮件的人:

firstname,lastname,email,title
Harry,Potter,hpotter@hogwarts.edu,"Defeating your nemesis in 3 easy steps"
Jack,Reacher,reacher@covert.mil,"Hand-to-hand combat for beginners"
Mickey,Mouse,mmouse@disney.com,"Surviving public speaking with a squeaky voice"
Santa,Claus,sclaus@northpole.org,"Efficient list-making"

你要读取 CSV 文件,替换第一个文件中的相关字段(跳过第一行),然后把结果写到一个叫 acceptanceN.txt 的文件中,每解析一行就递增文件名中的 N

awk 程序写在一个叫 mail_merge.awk 的文件中。在 awk 脚本中的语句用 ; 分隔。第一个任务是设置字段分隔符变量和其他几个脚本需要的变量。你还需要读取并丢弃 CSV 中的第一行,否则会创建一个以 Dear firstname 开头的文件。要做到这一点,请使用特殊函数 getline,并在读取后将记录计数器重置为 0。

BEGIN {
  FS=",";
  template="email_template.txt";
  output="acceptance";
  getline;
  NR=0;
}

主要功能非常简单:每处理一行,就为各种字段设置一个变量 —— firstnamelastnameemailtitle。模板文件被逐行读取,并使用函数 sub 将任何出现的特殊字符序列替换为相关变量的值。然后将该行以及所做的任何替换输出到输出文件中。

由于每行都要处理模板文件和不同的输出文件,所以在处理下一条记录之前,需要清理和关闭这些文件的文件句柄。

{
        # 从输入文件中读取关联字段
        firstname=$1;
        lastname=$2;
        email=$3;
        title=$4;

        # 设置输出文件名
        outfile=(output NR ".txt");

        # 从模板中读取一行,替换特定字段,
        # 并打印结果到输出文件。
        while ( (getline ln &lt; template) &gt; 0 )
        {
                sub(/{firstname}/,firstname,ln);
                sub(/{lastname}/,lastname,ln);
                sub(/{email}/,email,ln);
                sub(/{title}/,title,ln);
                print(ln) &gt; outfile;
        }

        # 关闭模板和输出文件,继续下一条记录
        close(outfile);
        close(template);
}

你已经完成了! 在命令行上运行该脚本:

awk -f mail_merge.awk proposals.csv

awk -f mail_merge.awk < proposals.csv

你会在当前目录下发现生成的文本文件。

awk 进阶:字频计数

awk 中最强大的功能之一是关联数组,在大多数编程语言中,数组条目通常由数字索引,但在 awk 中,数组由一个键字符串进行引用。你可以从上一节的文件 proposals.txt 中存储一个条目。例如,在一个单一的关联数组中,像这样:

        proposer["firstname"]=$1;
        proposer["lastname"]=$2;
        proposer["email"]=$3;
        proposer["title"]=$4;

这使得文本处理变得非常容易。一个使用了这个概念的简单的程序就是词频计数器。你可以解析一个文件,在每一行中分解出单词(忽略标点符号),对行中的每个单词进行递增计数器,然后输出文本中出现的前 20 个单词。

首先,在一个名为 wordcount.awk 的文件中,将字段分隔符设置为包含空格和标点符号的正则表达式:

BEGIN {
        # ignore 1 or more consecutive occurrences of the characters
        # in the character group below
        FS="[ .,:;()<>{}@!\"'\t]+";
}

接下来,主循环函数将遍历每个字段,忽略任何空字段(如果行末有标点符号,则会出现这种情况),并递增行中单词数:

{
        for (i = 1; i &lt;= NF; i++) {
                if ($i != "") {
                        words[$i]++;
                }
        }
}

最后,处理完文本后,使用 END 函数打印数组的内容,然后利用 awk 的能力,将输出的内容用管道输入 shell 命令,进行数字排序,并打印出 20 个最常出现的单词。

END {
        sort_head = "sort -k2 -nr | head -n 20";
        for (word in words) {
                printf "%s\t%d\n", word, words[word] | sort_head;
        }
        close (sort_head);
}

在这篇文章的早期草稿上运行这个脚本,会产生这样的输出:

[dneary@dhcp-49-32.bos.redhat.com]$ awk -f wordcount.awk < awk_article.txt
the     79
awk     41
a       39
and     33
of      32
in      27
to      26
is      25
line    23
for     23
will    22
file    21
we      16
We      15
with    12
which   12
by      12
this    11
output  11
function        11

下一步是什么?

如果你想了解更多关于 awk 编程的知识,我强烈推荐 Dale Dougherty 和 Arnold Robbins 所著的《Sed 和 awk》这本书。

awk 编程进阶的关键之一是掌握“扩展正则表达式”。awk 为你可能已经熟悉的 sed 正则表达式语法提供了几个强大的补充。

本文转载自: https://zhuanlan.zhihu.com/p/260109796复制
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 提升awk技能的两个教程【译】

    原文:https://opensource.com/article/19/10/advanced-awk

    程序员架构进阶
  • 15 个初学者 JavaScript 项目来提高你的前端技能!

    要成为一名优秀的 Web 开发人员,最快的方法就是练习。一个很好的练习方法是尽可能多地构建初学者项目。那是因为每个项目都会提出一个独特的问题和解决方案,因此您解...

    艾编程
  • 通过 20 个棘手的ES6面试问题来提高咱们的 JS 技能

    ECMAScript 6(以下简称ES6)是 JS 语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得 JS 语言可以用来编写复杂的大型应用程序...

    前端达人
  • 通过 20 个棘手的ES6面试问题来提高咱们的 JS 技能

    ECMAScript 6(以下简称ES6)是 JS 语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得 JS 语言可以用来编写复杂的大型应用程序...

    前端小智@大迁世界
  • Linux 三剑客之 awk 实战详解教程

    我们知道 Linux 三剑客,它们是 grep、sed、awk。在前边已经讲过 grep 和 sed,没看过的同学可以直接点击阅读,今天要分享的是更为强大的 a...

    用户3105362
  • 生信工程师入门最佳指南

    如果是想通过培训掌握生物信息学,那么可以参考:彻底入门生物信息学,可能需要12天! 推文介绍的。

    生信技能树
  • 把gwas信息转为bed格式

    这个时候需要把两个文件都弄成为bed格式, 然后使用 bedtools "intersect" 命令即可。

    生信技能树
  • 一记组合拳,批量SSH弱密码爆破检测工具分享

    SSH登录密码的破解工具已然有许多,但偶尔还是存在不能满足任务需求的情况。比如,批量地对IP列表里的IP地址进行SSH登录破解,现有的工具直接使用起来总觉得不方...

    FB客服
  • 简明AWK实战教程

    AWK是一个强大的格式化文本处理工具,一般在类Unix操作系统中都是必带的工具(Linux、Mac OS),因此,使用无需安装,非常的方便与便捷。

    流川枫
  • 为什么程序猿都应该学点linux命令?

    大家好,我是xindoo,今天和大家分享下一个我的观点——程序猿都应该学点Linux命令!这也是这两年我做后端开发的切身体会。认识我的人可能都知道,我职业生涯比...

    xindoo
  • 一个月学会Python的Quora指南和资料放送

    如何一个月学会使用Python 文章翻译自Quora上的回帖,略有改动。 原文链接:https://www.quora.com/What-are-the-bes...

    生信宝典
  • awk实现类sql的join操作

    awk、grep和sed被称为linux三剑客,事实上grep和awk我在日常工作中也常用到(sed用的比较少),可能有些人对awk了解比较少,我先大概介绍下。...

    xindoo
  • csvtk:高效命令行版极简dplyr

    之前写 datamash 的使用教程 linux 极简统计分析工具 datamash 必看教程,收到了一位读者的私信,内容如上。

    生信技能树
  • 扩充你的工具箱 - 大行文件的处理

    前言 前几天,从 DBA 手里接到一个 Redis RDB 文件,里面是 15G 约 660万 的 Redis 键值对数据,想通过这些数据提取出当前 Redis...

    枕边书
  • 一篇精辟的Linux必知必会​,推荐收藏

    SamGor:叉烧哥最近有篇关于linux的学习笔记,看完了觉得写得十分精辟,对于尚未使用linux的同学来说简直就是福音~推荐给大家学习学习。

    Sam Gor
  • 在Mac或者Linux上面安装velocyto.R的成功经验分享

    不过,除了服务器,我也在自己的苹果电脑上面试了试,在Mac操作系统还是蛮简单的,本来应该是就一句话安装啦:

    生信技能树
  • GATK4的gvcf流程

    得到了它们的bam文件,也是走的GATK流程,这里就不多说了。本教程首发于生信技能树VIP论坛:https://vip.biotrainee.com/d/423...

    生信技能树
  • 还是使用CCDS数据库的基因坐标信息来计算基因长度吧

    还是使用CCDS记录文件吧,CCDS 数据库旨在确定一组核心的人类和小鼠蛋白质编码区域,这些区域具有一致的注释和高质量。人类数据更新到了2018 年 ,包括了 ...

    生信技能树
  • 420小时学习代码之后:如何教你免费自学Python

    用户1148881

扫码关注腾讯云开发者

领取腾讯云代金券