Awk是什么
Awk、sed与grep,俗称Linux下的三剑客,它们之前有很多相似点,但是同样也各有各的特色,相似的地方是它们都可以匹配文本,其中sed和awk还可以用于文本编辑,而grep则不具备这个功用。sed是一种非交互式且面向字符流的编辑器(a “non-interactive” stream-oriented editor),而awk则是一门模式匹配的编程语言,因为它的主要功能是用于匹配文本并处理,同时它有一些编程语言才有的语法,例如函数、分支循环语句、变量等等,当然比起我们常见的编程语言,Awk相对比较简单。
使用Awk,我们可以做以下事情:
将文本文件视为由字段和记录组成的文本数据库;
在操作文本数据库的过程中能够使用变量;
能够使用数学运算和字符串操作;
能够使用常见的编程结构,例如条件分支与循环;
能够格式化输出;
能够自定义函数;
能够在awk脚本中执行UNIX命令;
能够处理UNIX命令的输出结果;
装备以上功能,awk能够做得事情非常多。但千里之行,始于足下,我们首先从最基本的命令行语法开始,一步一步得走入awk的编程世界。
命令行语法
同sed一样,awk的命令行语法也有两种形式:
这里的program类似sed中的script,因为我们一直强调awk是一门编程语言,所以将awk的脚本视为一段代码。而awk的脚本同样可以写到一个文件中,并通过-f参数指定,这一点和sed是一样的。program一般多个pattern和action序列组成,当读入的记录匹配pattern时,才会执行相应的action命令。这里有一点要注意,在第一种形式中,除去命令行选项外,program参数一定要位于第一个位置。
Awk的输入被解析成多个记录(Record),默认情况下,记录的分隔符是,因此可以认为一行就是一个记录,记录的分隔符可以通过内置变量RS更改。当记录匹配某个pattern时,才会执行后续的action命令。
而每个记录由进一步地被分隔成多个字段(Field),默认情况下字段的分隔符是空白符,例如空格、制表符等等,也可以通过-F ERE选项或者内置变量FS更改。在awk中,可以通过$1,$2…来访问对应位置的字段,同时$0存放整个记录,这一点有点类似shell下的命令行位置参数。关于这些内容,我们会在下面详细介绍,这里你只要知道有这些东西就好。
标准的awk命令行参数主要由以下三个:
-F ERE:定义字段分隔符,该选项的值可以是扩展的正则表达式(ERE);
-f progfile:指定awk脚本,可以同时指定多个脚本,它们会按照在命令行中出现的顺序连接在一起;
-v assignment:定义awk变量,形式同awk中的变量赋值,即name=value,赋值发生在awk处理文本之前;
为了便于理解,这里举几个简单的例子。通过-F参数设置冒号:为分隔符,并打印各个字段:
在awk的脚本中访问通过-v选项设置的变量:
从上面可以看到,通过-v选项设置的变量在BEGIN的位置就可以访问了。BEGIN是一个特殊的pattern,它在awk处理输入之前就会执行,可以认为是一个初始化语句,与此对应的还有END。
好像还没介绍如何指定处理的文件,是不是最后的argument就是指定的文件?在看我这本书之前,我也是这样认为的,但是实际上arguemnt有两种形式,它们分别是输入文件(file)和变量赋值(assignment)。
awk可以同时指定多个输入文件,如果输入文件的文件名为’-‘,表示从标准输入读取内容。
变量赋值类似-v选项,它的形式为name=value。awk中的变量名同一般的编程语言无太多区别,但是不能同awk的保留关键字重名,可以查看awk的man手册查询哪些是保留关键字。而变量值只有两种形式:字符串和数值。变量赋值必须位于脚本参数的后面,与文件名参数无先后顺序的要求,但是位于不同位置的赋值它的执行时机是不同的。
我们用实际的例子来解释这个区别,假设有两个文件:a和b,它们的内容分别如下所示:
为了说明赋值操作发生的时机,我们在BEGIN,正常处理,END三个地方都打印变量的值。
第一种情况: 变量赋值位于所有文件名参数之前
结果:赋值操作发生在正常处理之前,BEGIN动作之后。
第二种情况:变量赋值位于所有文件名之后:
结果:赋值操作发生在正常处理之后,END动作之前。
第三种情况:变量赋值位于文件名之间:
结果:赋值操作发生在处理前面的文件之后,并且位于处理后面的文件之前;
总结如下:
如果变量赋值在第一个文件参数之前,在BEGIN动作之后执行,影响到正常处理和END动作;
如果变量赋值在最后一个文件参数之后,在END动作之前执行,仅影响END动作;
如果文件参数不存在,情况同1所述;
如果变量赋值位于多个文件参数之间,在变量赋值前面的文件被处理后执行,影响到后续文件的处理和END动作;
所以变量赋值一定要考虑清楚用途,否则比较容易出错,不过一般情况下也不会用到变量赋值。
自然地大家会将变量赋值与-v assignment选项进行比较,赋值的形式是一致的,但是-v选项的执行时机比变量赋值要早:
可见,-v选项的赋值操作在BEGIN动作之前就执行了。
变量赋值一定要小心不要与保留关键字重名,否则会报错: