linuxawk函数定义变量赋值,Linux中的Awk定义、⽤法详解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动作之前。
第三种情况:变量赋值位于⽂件名之间:
结果:赋值操作发⽣在处理前⾯的⽂件之后,并且位于处理后⾯的⽂件之前;
总结如下:
value函数什么意思如果变量赋值在第⼀个⽂件参数之前,在BEGIN动作之后执⾏,影响到正常处理和END动作;
如果变量赋值在最后⼀个⽂件参数之后,在END动作之前执⾏,仅影响END动作;
如果⽂件参数不存在,情况同1所述;
如果变量赋值位于多个⽂件参数之间,在变量赋值前⾯的⽂件被处理后执⾏,影响到后续⽂件的处理和END动作;
所以变量赋值⼀定要考虑清楚⽤途,否则⽐较容易出错,不过⼀般情况下也不会⽤到变量赋值。
⾃然地⼤家会将变量赋值与-v assignment选项进⾏⽐较,赋值的形式是⼀致的,但是-v选项的执⾏时机⽐变量赋值要早:
可见,-v选项的赋值操作在BEGIN动作之前就执⾏了。
变量赋值⼀定要⼩⼼不要与保留关键字重名,否则会报错:
记录(Record)与字段(Field)
对于数据库来说,⼀个数据库表是由多条记录组成的,每⼀⾏表⽰⼀条记录(Record)。每条记录由多列
组成,每⼀列表⽰⼀个字段(Field)。Awk将⼀个⽂本⽂件视为⼀个⽂本数据库,因此它也有记录和字段的概念。默认情况下,记录的分隔符是回车,字段的分隔符是空⽩符,所以⽂本⽂件的每⼀⾏表⽰⼀个记录,⽽每⼀⾏中的内容被空⽩分隔成多个字段。利⽤字段和记录,awk就可以⾮常灵活地处理⽂件的内容。
可以通过-F选项来修改默认的字段分隔符,例如/etc/passwd的每⼀⾏都是由冒号分隔成多个字段的,所以这⾥就需要将分隔符设置成冒号:
这⾥通过$1引⽤第⼀⼈字段,类似地$2表⽰第⼆个字段,$3表⽰第三个字段…. $0则表⽰整个记录。内置变量NF记录着字段的个数,所以$NF表⽰最后⼀个字段:
当然,$(NF-1)表⽰倒数第⼆个。
内置变量FS也可以⽤于更改字段分隔符,它记录着当前的字段分隔符:
记录的分隔符可以通过内置变量RS更改:
如果将RS设置成空,⾏为有就⼀点怪异了,它会将连续不为空⾏的所有⾏(⼀个段落)当作⼀个记录,⽽且强制回车为字段分隔符:
这⾥,我们将变量赋值放到BEGIN动作中执⾏,因为BEGIN动作是在⽂件处理之前执⾏的,专门⽤于放初始化的语句。FS的赋值在这⾥是⽆效的,awk依然使⽤回车符来分隔字段。
脚本(Script)组成
命令⾏中的program部分,可以称为awk代码,也可以称为awk脚本。⼀段awk脚本是由多个’pattern { ac
tion }‘序列组成的。action是⼀个或者多个语句,它在输⼊⾏匹配pattern的时候被执⾏。如果pattern为空,表明这个action会在每⼀⾏处理时都会被执⾏。下⾯的例⼦简单地打印⽂件的每⼀⾏,这⾥不带任何参数的print语句打印的是整个记录,类似’print $0‘:
除了pattern { action },还可以在脚本中定义⾃定义的函数,函数定义格式如下所⽰:
函数的参数列表⽤逗号分隔,参数默认是局部变量,⽆法在函数之外访问,⽽在函数中定义的变量为全局变量,可以在函数之外访问,如:
Awk脚本中的语句使⽤空⾏或者分号分隔,使⽤分号可以放在同⼀⾏,不过有时候会影响可读性,尤其是分⽀或循环结构中,很容易出错。如果Awk中的⼀个语句太长,要分成多⾏,可以在⾏为使⽤反斜杠’':
这⾥我们将脚本写到⽂件中,并通过-f参数来指定。但是,在⼀些特殊符号之后,是可以直接换⾏的,例如”, { &&
”。
模式(Pattern)
模式是awk中⽐较重要的⼀部分,它有以下⼏种情况:
/regular expression/: 扩展的正则表达式(Extended Regular Expression), 关于ERE可以参考这篇⽂章;
relational expression: 关系表达式,例如⼤于、⼩于、等于,关系表达式结果为true表⽰匹配;
BEGIN: 特殊的模式,在第⼀个记录处理之前被执⾏,常⽤于初始化语句的执⾏;
END: 特殊的模式,在最后⼀个记录处理之前被执⾏,常⽤于输出汇总信息;
pattern, pattern:模式对,匹配两者之间的所有记录,类似sed的地址对;
例如查匹配数字3的⾏:
相反地,可以在在正则表达式之前加上’!’表⽰不匹配:
除了BEGIN和END这两个特殊的模式外,其余的模式都可以使⽤’&&’或者’
’运算符组合,前者表⽰逻辑与,后者表⽰逻辑或:
前⾯的正则都是整⾏匹配,有时候仅仅需要匹配某个字符,这样我们可以⽤表达式$n ~ /ere/:
有时候我们只想显⽰特定和⾏,例如显⽰第⼀⾏:
正则表达式(Regular Expression)
正则表达式的内容介绍起来太⿇烦,还是推荐同学阅读现有的⽂章(如Linux/Unix⼯具与正则表达式的POSIX规范),⾥⾯对各个流派的正则表达式归纳地很清楚了。
表达式(Expressions)
表达式可以由常量、变量、运算符和函数组成,常数和变量的值可以为字符串和数值。
Awk中的变量有三种类型:⽤户定义的变量,内置变量和字段变量。其中,内置变量名都是⼤写的。变量并不⾮⼀定要被声明或者被初始化,未初始化的字符串变量的值为””,未初始化的数值变量的值为0。字段变量可以⽤$n来引⽤,n的取值范围为[0,NF]。n可以为⼀个变量,例如$NF代码最后⼀个字段,⽽$(NF-1)表⽰倒数第⼆个字段。
数组
数组是⼀种特殊的变量,在awk中,⽐较特殊地是,数组的下标可以为数字或者字符串。数组的赋值很简单,下⾯将value赋值给数组下标为index的元素:array[index]=value
可以⽤for..in..语法遍历数组元素,其中item是数组元素对应的下标:for (item in array)
当然也可以在if分⽀判断中使⽤in操作符:if (item in array)
⼀个完整的例⼦如下所⽰:
内置变量
Awk在内部维护了许多内置变量,或者称为系统变量,例如之前提到的FS、RS等等。常见的内置变量如下表所⽰
变量名
描述
ARGC
命令⾏参数的各个,即ARGV数组的长度
ARGV
存放命令⾏参数
CONVFMT
定义awk内部数值转换成字符串的格式,默认值为”%.6g”
OFMT
定义输出时数值转换成字符串的格式,默认值为”%.6g”
ENVIRON
存放系统环境变量的关联数组
FILENAME