关于awk:Linuxawk命令介绍

引言Awk是一种用于高级文本处理的通用脚本语言,其次要用作报告和剖析工具,与大多数其余程序性编程语言不同,Awk是数据驱动的,也就是说须要定义一组针对输出文本要执行的操作,而后其获取输出数据,对其进行转换,而后将后果发送到规范输入。 语法awk [ -F fs ] [ -v var=value ] [ 'prog' | -f progfile ] [ file ... ]参数-F fs: 将输出字段分隔符设置为正则表达式fs。-v var=value: 在执行awk程序之前,将值赋值给变量var。'prog': awk程序。-f progfile: 指定文件progfile,其中蕴含要执行的awk程序。file ...: 由指定的awk程序处理的文件。示例示例文件example.txt文件内容如下: Bucks Milwaukee 60 22 0.732 Raptors Toronto 55 24 0.707 76ers Philadelphia 51 31 0.622Celtics Boston 33 33 0.598Pacers Indiana 30 34 0.585输入example.txt的第3个字段。 awk '{ print $3 }' example.txt# 60# 55# 51# 33# 30应用正则表达式匹配出以R结尾的组。 awk '/^R/ { print $1,$2,$3,$4 }' example.txt# Raptors Toronto 55 24应用BEGIN以及END输入在解决记录之前与之后执行的操作,处理过程为输入第二个字段蕴含Tor的组。 ...

February 28, 2023 · 1 min · jiezi

关于awk:超有用的-Linux-Unix-awk-命令示例

awk 是一种脚本语言,用于解决或剖析文本文件。或者咱们能够说,awk 命令次要用于依据列或字段或一组列对数据进行分组,它次要用于以有用的形式报告数据,它还应用 Begin 和 End 块来解决数据。 awk 名声在外,然而很少有人晓得它的违心是什么,awk 代表 “Aho, Weinberger, and Kernighan”,又见伯格系列,如果有一天中国人的工具用人名来命名会是啥样子? 根本语法# awk ‘pattern {action}’ input-file > output-file咱们先创立一个蕴含以下数据的输出文件 $ cat awk_fileName,Marks,Max MarksRam,200,1000Shyam,500,1000Ghyansham,1000Abharam,800,1000Hari,600,1000Ram,400,1000(1) 打印所有行默认状况下,awk 打印文件的所有行,示例如下 $ awk '{print;}' awk_fileName,Marks,Max MarksRam,200,1000Shyam,500,1000Ghyansham,1000Abharam,800,1000Hari,600,1000Ram,400,1000备注: 在 awk 命令中 {print;} 用于打印所有字段及其值。 (2) 只打印特定的字段在 awk 命令中,咱们应用 $ (美元) 符号后跟字段号来打印字段值。 咱们只打印字段 2 和字段 3,应用选项 -F,指定逗号为字段分隔符。 $ awk -F "," '{print $2, $3;}' awk_fileMarks Max Marks200 1000500 10001000800 1000600 1000400 1000(3) 打印与模式匹配的行打印蕴含单词 Hari 或 Ram 的行,示例如下 ...

February 24, 2023 · 1 min · jiezi

一次定时任务配置错误引发的思考

背景某业务人员反应系统登陆不上去,于是程序员自己试着登陆系统成功了,心里很自信的认为“我的代码没有问题”,便让业务人员再试试。然后业务人员是登陆成功了,但是整个系统用起来很卡,这下程序员意识到是系统的问题了。 排查步骤因为刚刚上线了新的功能,想到了配置了定时任务,可能是定时任务配置错误,导致PHP启了过多进程。 使用命令ps -ef | grep php 查看,果然是起了很多没必要的更新数据脚本,其中涉及到与第三方接口的交互并且有大量的更新数据库的操作,所以直接导致系统卡顿。 使用命令crontab -l查看crontab配置,有几个脚本的执行频率是想配置成每小时执行一次,结果配置错误,导致每分钟执行一次。具体如下: # 错误配置* */1 * * * /usr/local/bin/php /data/site/demo/yii demo/sync-product# 正确配置0 */1 * * * /usr/local/bin/php /data/site/demo/yii demo/sync-product问题是排查到了,现在需要做的就是快速kill掉那些没必要的进程。这时候便想到了万能的awk命令,如下: ps -ef | grep php | awk '{print $2}' | xargs kill -9执行后,系统开始恢复稳定。 思考整个问题排查总结下来,归根结底还是配置crontab是不够细心。 同时也引发了其他的一些思考,总结后整理如下: 系统突然出现卡顿,常用的排查思路有哪些呢?查看内存使用状况:free -g查看磁盘使用状况:df -h查看磁盘I/O使用:iostat -dx查看CPU使用:top具体的系统调优,本文不做介绍了。 awk命令的基本使用常用命令 awk '条件类型 1{动作1} 条件类型2{动作2} ...' filenameawk后面接两个引号并加上大括号来设置想要对数据进行的处理动作。 例如:我们要取出账号与登录者的IP,且之间以[TAB]隔开,则: [release@api_02 ~]$ last -n 5 | awk '{print $1 "\t" $3}'release 117.111.111.11release 117.111.111.11release 117.111.111.11release 117.111.111.11release 117.111.111.11awk还存在一些内置变量 ...

October 16, 2019 · 1 min · jiezi

Linux三剑客之awk详解

第一篇 awk简介与表达式实例一种名字怪异的语言模式扫描和处理,处理数据和生成报告。awk不仅仅是linux系统中的一个命令,而且是一种编程语言;它可以用来处理数据和生成报告(excel);处理的数据可以是一个或多个文件;可以是直接来自标准输入,也可以通过管道获取标准输入;awk可以在命令行上直接编辑命令进行操作,也可以编写成awk程序来进行更为复杂的运用。 sed处理stream editor文本流,水流。 一、awk环境简介本文涉及的awk为gawk,即GNU版本的awk。 [root@creditease awk]# cat /etc/redhat-releaseCentOS Linux release 7.5.1804 (Core)[root@creditease awk]# uname -r3.10.0-862.el7.x86_64[root@creditease awk]# ll `which awk`lrwxrwxrwx. 1 root root 4 Nov 7 14:47 /usr/bin/awk -> gawk [root@creditease awk]# awk --versionGNU Awk 4.0.2二、awk的格式awk指令是由模式、动作,或者模式和动作的组合组成。 模式即pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把它理解为一个条件。动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。如下awk使用格式。三、记录和域名称含义record记录,行filed域,区域,字段,列1)NF(number of field)表示一行中的区域(列)数量,$NF取最后一个区域。 2)$符号表示取某个列(区域),$1,$2,$NF 3)NR (number of record) 行号,awk对每一行的记录号都有一个内置变量NR来保存,每处理完一条记录NR的值就会自动+1 4)FS(-F)field separator 列分隔符,以什么把行分隔成多列 3.1 指定分隔符[root@creditease awk]# awk -F "#" '{print $NF}' awk.txt GKL$123GKL$213GKL$321[root@creditease awk]# awk -F '[#$]' '{print $NF}' awk.txt 1232133213.2 条件动作基本的条件和动作[root@creditease awk]# cat awk.txt ABC#DEF#GHI#GKL$123BAC#DEF#GHI#GKL$213CBA#DEF#GHI#GKL$321[root@creditease awk]# awk -F "#" 'NR==1{print $1}' awk.txtABC3.3 只有条件 [root@creditease awk]# awk -F "#" 'NR==1' awk.txtABC#DEF#GHI#GKL$123默认会有动作{print $0} ...

June 19, 2019 · 5 min · jiezi

awk详解

AWK简介AWK是一种优良的文本处理工具。它不仅是 Linux 中也是任何环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言:AWK 程序设计语言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。 使用方法awk '{pattern + action}' {filenames} 尽管操作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。 调用awk命令行方式awk [-F field-separator] 'commands' input-file(s)其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。 shell脚本方式将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。相当于shell脚本首行的:#!/bin/sh可以换成:#!/bin/awk 将所有的awk命令插入一个单独文件,然后调用:awk -f awk-script-file input-file(s)其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。 入门实例(取出linux最近登录的五个用户的用户名) # 下面是取出最近登录的五个用户的信息[root@localhost ~]# last -n 5root pts/1 192.168.1.100 Tue Feb 10 11:21 still logged intest pts/1 192.168.1.100 Tue Feb 10 00:46 - 02:28 (01:41)root pts/1 192.168.1.100 Mon Feb 9 11:41 - 18:30 (06:48)dmtsai pts/1 192.168.1.100 Mon Feb 9 11:41 - 11:41 (00:00)root tty1 120.239.75.53 Fri Sep 5 14:09 - 14:10 (00:01)# 如果只是显示最近登录的5个帐号的用户名$ last -n 5 | awk '{print $1}'roottestrootdmtsairoot# awk工作流程是这样的:读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域,$1表示第一个域,$n表示第n个域。默认域分隔符是"空白键" 或 "[tab]键",所以$1表示登录用户,$3表示登录用户ip,以此类推。入门实例(只显示/etc/passwd的账户) ...

April 27, 2019 · 3 min · jiezi

awk 列传

awk 是一种专事文本解析与处理的解释型编程语言,其解释器与其同名注 1。awk 原始版本发布于 1977 年,后于 1985 年发布第一个增强版本。在这一时期,awk 羽翼渐丰,随后成为 Unix 系统的一个标准(POSIX 标准)组件。目前 Linux 系统配备的 awk 皆为 gawk,隶属 GNU 项目,伊始于 1986 年。注 1:awk 得名于它的三位开发者 Alfred V. Aho、Peter J. Weinberger 以及 Brian W. Kernighan 名字的首字母。awk 的设计深受 Unix 系统中的文本检索工具 grep 与文本编辑工具 sed 的启发,其语法借鉴了 C 语言。模式-动作「模式-动作」逻辑是 awk 语言的精华所在。awk 认为自身所处理的文本文件里依序存储着一组记录。awk 默认将文件中的每一行视为一条记录注 2,通过模式检索特定记录,而后通过动作修改记录的内容。模式由逻辑表达式或正则表达式构成,而动作则由一组用于分析或处理文本的语句构成。在 awk 解释器看来,模式和动作形成的整体即程序,文件里的每条记录则为程序的输入数据,而动作所产生的结果则为程序的输出数据。注 2:下文在讲述记录分割符变量 RS 时,再给出让 awk 将多行文本视为一条记录的方法。例如,对于任意一份文本文件 foo.txt,若仅输出其第三行,可通过 awk 程序NR == 3 { print $0 }来实现,其中 NR == 3 为模式,而 print $0 为动作。NR 与 $0 皆为 awk 解释器内部维护的变量,前者用于保存 awk 解释器目前所读入的记录的序号,后者用于保存记录的内容。将上述 awk 程序以及 foo.txt 作为 awk 解释器的输入数据,即在终端中执行$ awk ‘NR == 3 { print $0 }’ foo.txt则 awk 解释器的输出结果即为 foo.txt 的第三行——awk 解释器默认将其视为第三条记录。为了防止 Shell 误解 awk 程序中的一些成分,必须将后者用单引号拘禁。上述命令诠释了 awk 解释器、awk 程序以及所处理的文本文件这三者之间的联系。在 awk 的实际应用中,我们需要对所处理的文本文件中的记录有足够的了解,剩下的任务则是编写 awk 程序,即模式 { 动作 }awk 解释器会顺序读取所处理的文本文件里的每一条记录,并验证它是否与模式相匹配。凡是与模式相匹配的记录,便会受模式之后的动作的操控。模式-动作可叠加起来作用于文件的每一条记录。例如,awk ‘NR == 3 { print $0 }; NR == 4 { print $0 }’ foo.txt可以输出 foo.txt 的第 3、4 行。不妨将 awk 程序里的动作理解为电路,将模式理解为开关。记录与模式匹配时,相当于触动了开关,使得电路得以导通。多条模式-动作,相当于有多个候选的开关及电路。模式可以为空,例如$ awk ‘{ print $0 }’ foo.txt此时,awk 会将动作作用于每一条记录。类似地,动作也可以为空,例如$ awk ‘NR == 3’ foo.txt此时,awk 会输出与模式相匹配的每一条记录,这一动作正是 { print $0 }。模式-动作的逻辑本质上是所有编程语言中的条件分支结构的泛化。Erlang、Racket、OCaml、Haskell、Swift 等语言提供了令其爱好者们引以为傲的模式匹配的语法所反映的也是这一逻辑。现在,知道了早在 1977 年 awk 便已经极为自然地建立了这一逻辑,应当由衷而叹,太阳底下果然没什么新鲜事!脚本为了让 awk 解释器能够在读取文件之前以及所有记录处理殆尽之后也能够有所动作,awk 语言提供了 BEGIN 和 END 这两个特殊的模式。因此较为完整的 awk 程序,其结构通常为BEGIN { 读取文件之前的动作 }模式 1 { 动作 1 }模式 2 { 动作 2 }… … …模式 n { 动作 n }END { 所有记录处理殆尽之后的动作 }如此便难以在终端里以命令参数的形式将程序交于 awk 解释器。再者,对于复杂的 awk 程序,若欲重复使用,命令参数的形式也多极为不便。为此,awk 解释器支持以脚本的形式载入程序,亦即可将 awk 程序保存为一份文件,而后让 awk 读取该文件以获得程序。此种文件即 awk 脚本。awk 解释器可通过 -f 选项载入脚本中的程序。例如,制作一份简单的 awk 脚本 hello-world.awk,$ cat << ‘EOF’ > hello-world.awkBEGIN { print “Hello”}NR == 5 { print $0}NR == 6 { print $0}END { print “world!"}EOF然后随意建立一份文本文件 foo.txt,$ cat << EOF > foo.txt以指喻指之非指不若以非指喻指之非指也以马喻马之非马不若以非马喻马之非马也天地一指也万物一马也EOF若执行$ awk -f hello-world.awk foo.txt则结果为Hello天地一指也万物一马也world!脚本 hello-world.awk 的内容可简化为BEGIN { print “Hello”}NR == 5 || NR == 6 { print $0}END { print “world!"}还可进一步简化为BEGIN { print “Hello”}NR == 5 || NR == 6END { print “world!”}|| 是逻辑运算「或」。awk 中基本的逻辑运算符号皆与 C语言同。在 awk 语言中,; 与换行等价,因此上述内容亦可写为BEGIN { print “Hello” }; NR == 5 || NR == 6; END { print “world!"}流程控制语句awk 提供了 if … else if … else 条件分支以及 for、while、do … while 等循环结构的语法,用法几近于 C 语言,无需赘述。正则表达式若使用正则表达式作为模式,则记录与模式的匹配所表示的逻辑是前者包含着可与后者匹配的文本。例如,若只输出上一节的 foo.txt 文件中含有「马」的记录,可以用 马 作为模式,$ awk ‘/马/’ foo.txt以马喻马之非马不若以非马喻马之非马也万物一马也awk 解释器输出的是 foo.txt 文件中含有可与正则表达式 马 匹配的文本的记录。在 awk 语言中,正则表达式的两侧以 / 为界。下面给出几个略微复杂一点的正则表达式作为模式的例子。只输出 foo.txt 中以 不若 作为开头的记录,$ awk ‘/^不若/’ foo.txt不若以非指喻指之非指也不若以非马喻马之非马也只输出 foo.txt 中以 也 作为结尾的记录,$ awk ‘/也$/’ foo.txt不若以非指喻指之非指也不若以非马喻马之非马也天地一指也万物一马也只输出 foo.txt 中含有至少两个 马 字的记录,$ awk ‘/马.*马/’ foo.txt以马喻马之非马不若以非马喻马之非马也awk 的正则表达式取自 egrep。egrep 为 grep 的扩展版本,支持的正则表达式较 grep 更为丰富。因此若熟悉 awk 的正则表达式,则自会熟悉 grep/egrep 的用法,反之亦然。对于正则表达式与记录的匹配,awk 提供了逻辑运算符 ~ 与 !,前者类似 ==,表示匹配,而后者类似 !=,表示不匹配。因此$ awk ‘/马.*马/’ foo.txt可写为$ awk ‘$0 ~ /马.*马/’ foo.txt还可以写为$ awk ‘{ if ($0 ~ /马.*马/) print $0 }’ foo.txt变量awk 的变量可无需初始化便可使用。例如,$ awk ‘NR == 1 { print a; print a + 1 }’ foo.txt1即输出了空行和内容为 1 的行。之所以会输出空行,是因为变量 a 未经初始化便在语句「print a」中使用,awk 解释器默认其值为空文本,即 “",从而导致 「print a」输出空行。但是在「print a + 1」中,awk 解释器发现 a 出现于算术表达式中,因此便将其值由空字串转化为数字 0,从而导致「print a + 1」输出内容为 1 的行。事实上,awk 的变量只有两种类型,文本和数字。awk 解释器会根据变量是否出现于算术表达式之中而对其值为文本还是数字进行推断。在 awk 程序中,所有的变量皆为全局变量,除非它以函数的参数形式出现。函数awk 的函数,其一般形式为function 函数名(参数 1, 参数 2, …, 参数 n) { 函数体}函数的调用与 C 同,但函数名与参数列表的左括号之间不能存在空格。在函数中,除了作为参数的变量,其他所有变量皆能为函数外部可见。例如,$ cat << ‘EOF’ > func-test.awkNR == 1 { t = mul(2, 3) print “t = " t “; z = " z “; x = " x}function mul(x, y) { z = x * y return z}EOF$ awk -f func-test.awk foo.txtt = 6; z = 6; x = 在与模式 NR == 1 相应的动作里,虽未对变量 z 进行赋值,但程序的输出结果却表明其值为 6,这是因为函数 mul 中的变量 z 在函数的外部可见。不过,在动作里调用 mul 时,将 2 赋予函数的参数 x,但动作输出的 x,其值为空文本。因此,若在 awk 程序中对变量的作用域进行限定,唯一的办法是让变量以函数参数的形式出现。awk 的变量颇类似 Bash,但 Bash 在函数内部可通过关键字 local 将变量的作用域限定在函数之内。不过,awk 的作者在函数的写法上给出了一个建议:可将作用域限定于函数内部的变量置于参数列表尾部,并通过一组空格,使之与函数的参数有所区分。例如,function mul(x, y, z) { z = x * y return z}awk 默认将变量作为全局变量的做法,使得编写一个略微复杂一些的程序的过程像是在编筐或织布,全局变量像是纬线,操作变量的语句则像是经线。数组awk 提供了数组类型。数组元素可以异构,但并非连续存储于一段内存空间。例如,a[0] = “abc”; a[1] = 7; a[2] = “马”; a[33] = “三十三"这个数组,虽然含有下标为 33 的元素,但是并非由 34 个元素构成,而是由 4 个元素构成,而且这 4 个元素在数组中的排列也未必是按照下标的顺序。awk 并未对数组元素的排列给出确切的定义,这主要依赖于 awk 解释器的具体实现。数组元素在排列上的不确定,意味着 awk 的数组仅支持顺序访问,但不支持随机访问。访问数组中的每个值,可采用 for (下标变量 in 数组) { … } 语法,例如,for (i in a) { print a[i] }若以for (i = 0; i < n; i++) { print a[i] }访问数组元素,前提是要保证数组元素的下标的确从 0 到 n。实际上,awk 数组的下标并非数字,而是文本。例如,a[3] 和 a[“3”] 皆能访问下标为 3 的元素。Bash 的数组亦如此。输入与输出命令$ awk ‘程序’ 文本文件或$ awk -f 脚本 文本文件是 awk 程序运行的一般方式。程序所需的外部数据可经由文本文件以记录的形式传入。若不向 awk 解释器提供文本文件,那么 awk 解释器便会将标准输入(stdin)作为程序所需的外部数据的来源。这意味着可以通过管道向 awk 程序传递记录。例如,以下程序可去除文本 " 白马非马 " 首尾的空白,$ echo " 白马非马 " | awk ‘{ match($0, / *([^ ]+) */, a); print a[1] }‘若利用 awk 的默认以空格作为列分隔符并且去除列内前导空白字符的特性,可将上述 awk 程序简化为$ echo " 白马非马 " | awk ‘{ print $1 }‘awk 解释器对于每条记录,默认以空白字符作为分割符,将记录内容斩为多段,每一段称为域;awk 会将域的数量存于内置变量 NF。域的内容依次存于 awk 解释器的内置变量 $1、$2、…、$n,并将各段内容的前导空白字符(空格或制表符)消除。$0 存储未分割的整条记录。对记录进行分割,这一特性使得 awk 程序在处理类似矩阵形式的文本表现的简短精悍,经常能以简短的一行程序完成其他编程语言动辄需要数十行代码方能完成的任务。例如,假设文件 emp.txt 内容为张三 4.00 0李四 3.75 0王五 4.00 10郑六 5.00 20赵七 5.50 22孙八 4.25 18记录了一组雇员的姓名、时薪以及工作时长。现在要制作一份薪水报表,即统计哪些人参与了工作,应发多少钱。若采用 awk 完成该任务,只需$ awk ‘$3 > 0 { print $1 “\t” $2 * $3 }’ emp.txt结果可得王五 40郑六 100赵七 121孙八 76.5若不仅给出每个人的薪水情况,还要给出总的支出金额,只需$ awk ‘$3 > 0 { x = $2 * $3; s += x; print $1 “\t” x }; END {print “\n总额\t” s}’ emp.txt王五 40郑六 100赵七 121孙八 76.5总额 337.5awk 解释器的内置变量 RS 和 FS 分别用于设定记录分割符和域分割符,亦即通过设定此二者,能够让 awk 解释器以记录和域的形式理解输入的数据。显然,应当在 awk 解释器读取文件设置 RS 和 FS,因此,它们的设定应当在 BEGIN 模式所对应的动作里进行,例如,BEGIN { RS = FS = "” }此时,RS 和 FS 皆为空文本,但二者含义不同,前者表示一个或多个空行作为记录分割符,而后者则以空文本作为域分割符。对于 Markdown 格式的中文文档,各个段落以一个或多个空行隔开,而各个汉字之间则以空文本隔开。若将 RS 和 FS 设为空文本,那么便可以很容易写出一个统计文档中汉字频率的 awk 程序。例如,统计一份文档中出现最多的十个汉字,只需BEGIN { RS = FS = "” }{ # 移除标点符号、数字、英文字母以及空白字符 gsub(/[.,:;!?(){}’",。:;!?()《》“” ‘’a-zA-Z0-9 ]/, “”) for (i = 1; i <= NF; i++) count[$i]++ }END { for (i in count) print i, count[i] | “sort -rn -k 2 | head” }我用这个程序统计的《庄子·逍遥游》中出现最多的十个汉字及出现次数为之 70而 55也 51不 42其 35者 26为 25无 24大 24有 22上述的 awk 程序,在实现汉字出现次数的排序以及排序结果的部分输出时,借助了 awk 的 print 函数与 sort 和 head 命令的管道衔接。此举似乎有些胜之不武,但是也没什么不妥,反而显现了 awk 在文本输出方面与 Linux(或其他类 Unix 系统)系统命令行环境的亲和性。awk 解释器通过 RS 与 FS 理解作为输入的文件。对于 awk 程序的输出,则存在这相应的变量 ORS 与 OFS,awk 解释器通过它们理解如何将程序所得结果输出。结语一些繁琐的文本分析方面的问题,通常能够以简短的 awk 程序来解决。有些人由此看到了 awk 之美,有些人看到的则是 awk 之丑。因此,awk 的一行程序,吸引了许多人,也吓走了许多人。在我看来,awk 不美,不丑,也不老。像大多数依然健在的古老的工具那样,只做一些恰如其分的事,这反而使之难以被取代。egrep 和 sed 也只做恰如其分之事,前者专事文件检索,后者专事文本编辑。此二者所具有的功能,awk 皆能实现,但 awk 的出现并未取代它们。因为有些任务,用 grep 和 sed 可以更快捷地完成,而用 awk 就有些繁琐。例如,若获取 foo.txt 中至少含有两个 马 字的行及其序号,可完成这一任务的 awk 命令为$ awk ‘/马.*马/ { print NR “:” $0 }’ foo.txt若是用 egrep,只需$ egrep -n ‘马.*马’ foo.txt若删除 foo.txt 文件中以 天地 和 万物 开始的行,可完成这一任务的 awk 命令为$ awk ‘$0 ! /^天地/ || ‘$0 !~ /^万物/’ foo.txt > new-foo.txt$ mv new-foo.txt foo.txt若是用 sed,只需$ sed -i ‘/^天地/d; /^万物/d’ foo.txt功能更强大的事物的出现,并不意味着功能孱弱的事物失去价值,反而可能更为彰显后者的价值。所以,不要随便地就对别人说,「我已习得 python,还有必要再学 awk 吗?」倘若 awk 不能而且无意于取代 egrep 和 sed,那么 python 当如何取代 awk 呢?本文所展现的 awk 功能约有十之六七,旨在揭示 awk 的主要功用。掌握这些功能,足以胜任常规的文本处理任务。本文中出现的文字注释形式,便是借助 awk 生成,程序为BEGIN { note_pat = “\\note{([^}]+)}” i = 1}{ # 注解 -> 上标 current_note = i while (x = match($0, note_pat, s)) { notes[i] = s[1] sub(note_pat, “<sup>注 " i++ “</sup>”, $0) } # 输出处理后的段落及注解列表 print $0 if (i > current_note) { # 段后增加注解 print "” it = current_note while (it < i) { print “> 注 " it “:” notes[it] it++ } }}有关 awk 的更为详尽的知识可从 awk 的三位开发者撰写的《The AWK Programming Language》一书中获得。这本书虽然写于 1988 年,但其内容依然适于现在的 awk 。此外,这本书在介绍 AWK 的编程示例中,言简意赅地介绍了文本处理、数据库、编译原理、排序以及图的遍历等计算机科学基础知识。也许每一本讲授编程语言的书,都应该借鉴《The AWK Programming Language》的写法。 ...

October 21, 2018 · 5 min · jiezi