AWK
Linux下AWK命令
- 1. AWK简介
- 2. AWK运行机制
- 3. AWK启动参数
- 4. AWK返回值
- 5. AWK模式
- 5.1 正则表达式
- 5.1.1. + (加号,plus sign)
- 5.1.2. ? (问号,question mark)
- 5.1.3. | (垂直线,vertical bar)
- 5.1.4. ( ) (小括号)
- 5.1.5. {m}
- 5.1.6. {m,}
- 5.1.7. {m,n}
- 5.1.8. [String]
- 5.1.9. [^ String]
- 5.1.10. ~~ 和 !~
- 5.1.11. ^(circumflex)
- 5.1.12. $ (dollar sign)
- 5.1.13. . (句号,period)
- 5.1.14. * (星号,asterisk)
- 5.1.15. \ (反斜杠,backslash)
- 5.1.16. 识别的转义序列:
- 5.2 关系表达式
- 5.3 模式的组合
- 5.4 BEGIN 和 END 模式
- 5.1 正则表达式
- 6. AWK变量
- 7. 操作符
- 8. AWK操作
- 9. 内置函数
- 10. 用户自定义函数
- 补充说明
1. AWK简介
1.1 AWK的功能
AWK被设计为一种方便的文本处理脚本。
1.2 AWK的限制
AWK只被设计为处理文本文件,不支持数据库、socket这样的特性。
AWK不支持用户扩展——和目前流行的TCL、Python这样的脚本不一样,AWK不支持用户扩展。也就是说,你的实现完全依赖于AWK自身所提供的功能,如果AWK没有提供相应的功能,用户自己是没有办法通过对AWK做一些修改来完成相应的功能的。
1.3 应用场所
虽然AWK存在一些限制,但是因为它属于UNIX的标准程序,在任何机器上都会有AWK的某种实现。加之本身的功能也还算比较强大,如果只是想实现文本挑选、转换这样的工作,还是建议使用,这样可以不受机器的限制。
另外,在进行SHELL编程时,常使用AWK来进行一些文字处理,比如,对命令 ps -ef 的结果进行处理,从中获取进程号。
1.4 如何学习
在C语言中,程序所执行的每个功能都是程序员写的,在AWK中,除了程序员所写的代码之外,还有AWK内置的一些机制,所以,要学习AWK编程,首先要了解AWK的工作原理,要知道AWK在代码之外都做了什么,具体可以参见“AWK运行机制”。
在了解AWK的机制之后,就可以沿着“模式、变量、语句、函数”的顺序依次学习。AWK的模式中,主要的内容是正则表达式,如果对正则表达式不太了解,也没有太大关系,只要知道模式的概念,就可以先学习后面的内容,等其它内容学完之后,再回过头来学习。
像特殊变量、内置函数、语句格式这样一些内容,能记住当然是最好不过的。有些记不住也没有太多关系,需要时再查看本文档或系统的man手册。
1.5 程序所在路程
本文所描述的AWK在各个操作系统下,分别位于:
AIX:/usr/bin/awk HP:/usr/bin/awk SUN:/usr/xpg4/bin/awk Linux: /bin/gawk
需要注意,在SUN下,有三个awk程序,/usr/bin/awk、/usr/bin/nawk 和 /usr/xpg4/bin/awk 。本文中所说的awk只 /usr/xpg4/bin/awk 。另外两个awk功能不完备,注意不要使用。
2. AWK运行机制
2.1 AWK机制介绍
一个AWK程序由一个或多个 pattern、action 语句组成,action 写在大括号里面。不同的 pattern、action 语句之间使用换行或分号来分隔。这样,AWK程序大致就形如:
pattern { action } pattern { action } ...... user-function
可以这样理解,pattern 是条件,action是动作。对待处理文件中的每一条记录,AWK会依次判断是否满足各个 pattern,如果满足,则执行对应的 action。一个 pattern、action 处理完后,会接着处理下一个 pattern、action ,直到将 AWK 程序中所有的 pattern、action 对处理完为止,这样才算对一条记录处理完毕。
pattern 或 action 可以被省略,但不能同时被省略:
- 如果 pattern 被省略,则对于输入文件的每一条记录,action都会被执行。
- 如果 action (包括大括号)被省略,则系统缺省会输出满足 pattern 的行。相当于action 是 { print $0 }
在action中,可以出现 if 、for 这样的分支、循环语句,所以,AWK具有一定的编程能力。
AWK会根据所指定的记录分隔符(RS),将待处理文件分隔成多个记录(record,通常一个记录就对应于文件中的一行)。再根据指定的字段分隔符(FS,缺省时是space,包括空格和tab),将每一行分隔成多个字段(field)。在AWK中,使用 $1、$2 ……、$n 来访问各个字段,而 $0 则表示整个记录。假设待处理文件内容为:
This is a dog. That is an apple.
如果使用缺省的RS和FS(分别是换行符和space),则AWK会先读取一行,“This is a dog.”,然后将其分成四个字段“this”、“is”、“a”和“dog.”。
AWK在将一条记录分隔成多个字段后,才会依照pattern在awk文件中出现的顺序依次匹配各个pattern。在一个patten匹配成功后,就会执行相应的action。可以参考下面的“完整的AWK流程”一节。
user-function是用户自定义的函数,可以放在AWK中的任意位置,我的建议是放在文件尾,这样比较好查看:打开一个AWK文件,首先看到的是业务的逻辑;看到最后,才需要涉及到相应的功能函数。
2.2 完整的AWK流程
可以使用下面的伪码来表示完整的AWK处理流程:
for (i = 0; i <启动参数中 -v Assignment 数目; i++) { 执行第 i 个 -v Assignment,为相应的变量赋值 } for (i = 0; i < BEGIN模式的数目; i++) { 处理第i个BEGIN模式对应的操作 } for (i = 0; i < 启动参数中 File 及 Assignment 参数的总个数; i++) { if (第 i 个参数是 Assignment) { 执行对应的Assignment,为相应的变量赋值 continue; } 打开第i个参数对应的待处理文件 while ( not 文件结束) { 根据RS,从待处理文件中读取一条记录 根据FS,将读取的记录分隔成不同的字段 for (j = 0; j < pattern的数目; j++) { if (第j个pattern匹配成功) //如果没有指定pattern,则总是匹配成功 { 执行对应的action //如果没有指定action,缺省为 print $0 } } // 所有pattern匹配结束 } // 一个文件处理结束 } // 所有文件都处理结束 for (i = 0; i < END模式的数目; i++) { 处理第i个END模式对应的操作 }
从上面的流程中可以看出,在AWK中,有三种不同优先级别的模式,按照优先级从高到低,依次是:BEGIN模式、普通模式(除了BEGIN和END之外的其它模式)、END模式。同一优先级的多个模式,AWK是执照在AWK文件中出现的先后顺序执行的。不同优先级的模式可以在AWK文件中按照任意顺序放置。
3. AWK启动参数
awk 启动格式为:
awk [ -F Ere ] [ -v Assignment ] ... { -f ProgramFile | 'Program' } [ [ File ... | Assignment ... ] ] ...
注意:启动参数的顺序是不能随便调整的,比如, -v Assignment 就不能放在 File 之后。所以,最保险的做法,就是严格执照上面顺序来写。
3.1 -F Ere
使用扩展正则表达式 Ere 作为字段分隔符(对应于特殊变量 FS)
3.2 -v Assignment
定义可以在AWK语言中访问的标量变量。
Assignment的格式为:Name=Value (注意,Name,=,Value三者之间不能有空格!),其中,Name是变量的名字,可以是任何以字符或下划线开头,后跟字母、下划线和数字的任意组合。Value是变量的值,可以是下划线、数字和字母的任意组合。且前面和后面都有一个”(双引号),如果Value部分是数字,则也将为变量指定对应的数字值。
通过 -v 标志指定的赋值操作发生在 BEGIN 操作之前,所以,可以在 BEGIN 操作中引用。
可以有多个 -v 标志,用来为多个变量赋值。
3.3 -f ProgramFile
从 ProgramFile 变量指定的文件名中获取 AWK 命令的指令。如果多次指定 -f 标志,则文件的串联(按照指定的顺序)将用作指令集。
3.4 'Program'
包含 awk 命令的指令。如果不指定 -f 标志,Program变量应该是命令行上的第一个项,并且应该包括在’’(单引号)中。如:
awk '{print $0}' x.unl
3.5 Assignment
和 “-v Assignment”的功能相同,只是执行的时间不一样。
Assignment 会在awk程序扫描到 Assignment 才被执行。可以参考“完整的AWK流程”一节。
注意,从AWK的流程中可以看出,BEGIN 操作中不能访问Assignment 所指定的变量!但可以访问 -v Assignment 所指定的变量。
3.6 File
指定包含要处理的输入的文件名称。如果不指定 File 变量,或指定了 - (减号),则处理标准输入。
4. AWK返回值
AWK命令返回值为:
返回值 | 含义 |
---|---|
0 | 表示成功执行完毕 |
>0 | 发生错误 |
如果是在 SHELL 编程中执行awk命令,则通常需要判断awk命令的返回值。
注意:可以通过在awk命令中使用 exit [Expression] 语句来更改程序的退出状态。
5. AWK模式
模式可以有以下几种类型:
5.1 正则表达式
awk所使用的扩展正则表达式类似于 grep 和 egrep 。当记录满足正则表达式的内容时,就认为模式匹配。
一个 regular expression 以斜线(‘/’)包围当作 AWK 的 pattern。如果输入记录含有 regexp 就视为符合。例如:pattern 为 /foo/,对於任何输入记录含有’foo’则视为符合。
awk '/foo/' input.txt
regexp 也能使用在比较的算式:
exp ~ /regexp/ :如果 exp 符合 regexp,则结果为真(true)。
exp !~ /regexp/ :如果 exp 不符合 regexp,则结果为真。
awk -F"|" '$2 ~ /abc/' f.unl # 打印出第2个字段包含 abc 的记录
假定一个名为 testfile 的文件具有以下内容:
smawley, andy smiley, allen smith, alan smithern, harry smithhern, anne smitters, alexis
格式约定:以“>>”作为命令行的提示符,
>> awk '/sm[a-h]/' testfile smawley, andy
表示执行命令 awk '/sm[^a-h]/' testfile,输出的结果为 smawley, andy 。
在正则表达式中,可以的特殊字符有:
5.1.1. + (加号,plus sign)
+表示重复前面的规则一次或多次。
>> awk '/smith+ern/' testfile smithern, harry smithhern, anne
将包含smit ,且后跟一个或多个 h ,再以 ern 结尾的字符串的记录打印至标准输出。
5.1.2. ? (问号,question mark)
?表示重复前面的规则零次或一次。
>> awk '/smith?/' testfile smith, alan smithern, harry smithhern, anne smitters, alexis
将包含smit ,后有零个或一个 h 字符的记录打印至标准输出。
5.1.3. | (垂直线,vertical bar)
垂直线表示多个规则中只要有一个满足就可以。
>> awk '/allen|alan/' testfile smiley, allen smith, alan
将包含字符串 allen 或 alan 的所有记录打印至标准输出。
5.1.4. ( ) (小括号)
( ) 用于将字符串组合在一起。
>> awk '/a(ll)?(nn)?e/' testfile smiley, allen smithhern, anne
将具有字符串 ae 或 alle 或 anne 或allnne 的所有记录打印至标准输出。
5.1.5. {m}
如果正好有m个模式的具体值位于字符串中,则字符串匹配。
>> awk '/l{2}/' testfile smiley, allen
将有2个l 的字符串打印至标准输出。
注:如果有多于2个l,比如, alllen,也算是匹配。为了避免这种情况,通常应该在{m}前、后再多指定一些模式。如:/al{2}en/,这样就只可能匹配 allen 。/al{2}en/是指在模式a和en中间含有且只有两个模式’l’,例如如果存在’acllben’和’alllen’用上述方法就匹配不出来。下面的 {m,} 和 {m,n} 也有类似的情况。
5.1.6. {m,}
如果至少有m个模式的具体值位于字符串中,则字符串匹配。如,
>> awk '/t{2,}/' testfile smitters, alexis
将至少有两个连续的 t 出现的记录打印至标准输出。
5.1.7. {m,n}
如果有m 和 n 之间(包括 m 和 n)个模式的具体值位于字符串中,则字符串匹配。
>> awk '/er{1,2}/' testfile smithern, harry smithhern, anne smitters, alexis
注:m、,(逗号)和n之间,不能有空格出现!
5.1.8. [String]
指定正则表达式与方括号内 String 变量指定的任何字符匹配。如:
>> awk '/sm[a-h]/' testfile smawley, andy
将具有 sm 后跟以字母 a 到 h 之间的任何字符的所有记录打印至标准输出。
如果是字母或数字存在连续的情况,则可以使用“起始字母-终止字母”的简写方式,如:[x-z] 表示从x到z的所有字母。如果是不连续字母/数值,则直接写出所有的单个字母,如[axz]表示a、x、z这三个字母。
^[ -_:0-9a-zA-Z]+$
表示由
5.1.9. [^ String]
在 [ ] (方括号)和在指定字符串开头的 ^ (插入记号)指明正则表达式与方括号内的任何字符不匹配。
>> awk '/sm[^a-h]/' testfile smiley, allen smith, alan smithern, harry smithhern, anne smitters, alexis
5.1.10. ~~ 和 !~
表示指定变量与正则表达式匹配(代字号)或不匹配(感叹号、代字号)的条件语句。
>> awk '$1 ~ /n/' testfile smithern, harry smithhern, anne
将第一个字段包含字符 n 的所有记录打印至标准输出。
5.1.11. ^(circumflex)
指定字段或记录的开头。
>> awk '$2 ~ /^h/' testfile smithern, harry
把字符 h 作为第二个字段的第一个字符的所有记录打印至标准输出。
5.1.12. $ (dollar sign)
指定字段或记录的末尾。
>> awk '$2 ~ /y$/' testfile smawley, andy smithern, harry
把字符 y 作为第二个字段的最后一个字符的所有记录打印至标准输出。
5.1.13. . (句号,period)
表示除了在空白末尾的终端换行字符以外的任何字符。
>> awk '/a..e/' testfile smawley, andy smiley, allen smithhern, anne
将具有两个字符隔开 a 和 e 所有记录打印至标准输出。
5.1.14. * (星号,asterisk)
表示重复前面的规则零次或多次。
>> awk '/a.*e/' testfile smawley, andy smiley, allen smithhern, anne smitters, alexis
将具有零个或多个字符隔开 a 和 e 所有记录打印至标准输出。
5.1.15. \ (反斜杠,backslash)
转义字符。当位于扩展正则表达式中具有特殊含义的任何字符之前时,转义字符除去该字符的任何特殊含义。如,
/a\/\//
将与模式 a// 匹配,因为反斜杠否定了斜杠作为正则表达式定界符的通常含义。要将反斜杠本身指定为字符,则使用两个反斜杠。
5.1.16. 识别的转义序列:
awk命令识别大多数C语言中约定的转义序列,以及awk命令本身用作特殊字符的几个转义序列。如下表:
转义序列 | 表示的字符 |
---|---|
\" | "(双引号)字符 |
\/ | /(斜杠)字符 |
\ddd | 其编码由1、2或3位八进制整数表示的字符,其中,d 表示一个八进制数位 |
\\ | \(反斜杠)字符 |
\a | 警告字符 |
\b | 退格字符 |
\f | 换页字符 |
\n | 换行字符 |
\r | 回车字符 |
\t | 跳格字符 |
\v | 垂直跳格字符 |
注:除了在 gsub、match、split 和 sub 内置函数中,扩展正则表达式的匹配都基于输入记录。记录分隔符(缺省情况下为换行字符)不能嵌套在表达式中,且没有与记录分隔符字符匹配的表达式(因为awk是先对记录、字段作了分隔,才进行匹配操作的)。如果记录分隔符不是换行字符,则可与换行字符匹配。在指定的四个内置函数中,匹配基于文本字符串,且任何字符(包含记录分隔符)可以嵌套在模式中,这样模式与适当的字符相匹配。然而,用awk命令进行 的所有正则表达式匹配中,在模式使用一个或多个NULL(空)字符将生成未定义的结果。
5.2 关系表达式
关系运算符 <(小于)、>(大于)、<=(小于或等于)、>=(大于或等于)、==(等于) 和 != (不等于)可以用来形成模式。例如,模式:
$1 < $4
将与第一个字段 小于第四个字段的记录匹配。
关系运算符还可以和字符串值一起使用,例如:
$1 != "q"
将与第一个字段不是q的所有记录匹配。
字符串值还可以根据校对值匹配,如:
$1 <= "d"
将与第一个字段以字符 a、b、c 或 d 开头的所有记录匹配。如果未给出其它信息,则字段变量作为字符串值进行比较。
5.3 模式的组合
可以使用三种选项组合模式:
- 范围由两种以 , (逗号)隔开的模式指定。 操作在每个以匹配第一个模式的记录开始的每个记录上执行,并通过匹配第二个模式的记录(包含此记录)继续。例如:
/begin/,/end/
与包含字符串 begin 的记录以及该记录和包含字符串 end 之间的所有记录(包括字符串 end 的记录)匹配。
- 括号() 将模式组合在一起。
- 布尔运算符
||
(或)、&&(和)以及 ! (不)将模式组合成如果它们求值为真则匹配,否则不匹配的表达式。例如,模式:
$1 == "al" && $2 == "123"
5.4 BEGIN 和 END 模式
- 用BEGIN模式指定的操作在读取任何输入之前执行。
- 用END指定的操作在读取了所有输入后执行。
- 允许多个BEGIN和END模式,并以指定的顺序处理它们。在程序语句中END模式可以在BEGIN模式之前。
- 如果程序仅由BEGIN语句构成,则执行操作且不读取输入。
- 如果程序仅由END语句构成,则在任何操作执行前读取所有输入。
6. AWK变量
AWK中的变量可以是标量(scalars)、数组(array elements)、字段变量(fields)和特殊变量。变量名称不能以数字开始。
AWK中的变量不需要在使用前先进行申明,变量可以具有数字值和/或字符串值,并根据上下文的不同而呈现出数字或字符串。
未初始化的标量变量和数组元素具有一个为0的数字值和一个为空串(””)的字符串值。
6.1. 特殊变量
AWK 自定义的特殊变量:
变量名 | 含义 |
---|---|
ARGC | 输入参数的个数,等同于C语言中的 argc,此值可以改变 |
ARGV | 输入参数数组,等同于C语言中的 argv |
CONVFMT | AWK内部运算时,将数字转换成字符串的 printf 格式。缺省值为”%.6g” 。 |
ENVIRON | 表示AWK运行环境的数组。使用 ENVIRON[“环境变量名”] 来访问某一环境变量的值。如: editor = ENVIRON[“EDITOR”] 。如果访问了不存在的环境变量,则返回一个空串。 |
FILENAME | AWK 当前处理的文件名 |
FNR | 当前处理文件的当前记录数 |
FS | 输入文件的字段分隔符,可以为单个字符,也可以是一个字符串。缺省值是(任意数目的)space (空格或跳格)。FS可以被指定为:\\1、单个字符:此时,字段由该字符的每个具体值隔开。如,指定为字符 “~|”,则每记录中每个 ~| 都被认为是分隔符。两个相邻的 ~| ,被认为是一个空字段。\\2、一个扩展正则表达式:字段由与扩展正则表达式匹配的每个序列的具体值隔开。这样,缺省的FS,可以被理解为: FS = “( ~|\t)+” \\除了在脚本中显示的指定外,还可以通过AWK的启动参数 -Ffs 来指定FS为 fs 所表示的正则表达式。 |
NF | 当前记录的字段个数,最大值为99 。 |
NR | 已读出的记录数,如果只是处理一个文件,则NR = FNR ,如果处理多个文件, NR >= FNR 。在BEGIN操作中,NR的值为0,在END操作中,NR的值为最后处理的记录的值。 |
OFMT | 在输出语句中将数字转换为字符串的printf格式。缺省值为”%.6g” 。 |
OFS | 输出文件的字段分隔符,可以为单个字符,也可以是一个字符串,缺省为空格 |
ORS | 输出文件的记录分隔符,缺省为换行(\n) |
RLENGTH | 由match函数来匹配的字符串的长度。(参见 match 函数的描述) |
RS | 输入文件的记录分隔符,缺省为换行(\n) (RS只有第一字符是是有效的,其它字符会被忽略) |
RSTART | 由 match 函数所匹配的字符串的起始位置,从1 开始编号。变量的值总是和 match 函数的返回值相同。(参见 match 函数的描述) |
SUBSEP | 多维数组中的下标分隔符。缺省值是"\034"。(详见“数组变量”的介绍) |
6.2. 标量变量
在AWK中,变量不需要先申明,直接对其赋值,然后就使用。如:
{ abc = 1; print abc }
将数字 1 赋值给变量 abc。
6.3. 数组变量
6.3.1. 概念介绍
数组初始为空且大小可以动态改变(类似于C++中的vector)。数组由一个变量名和在[](方括号)中的下标来标示。下标可以是数字,也可以是字符串。
数组可以用一个以上的下标来建立索引,以实现多维数组。AWK中数组实际上是一维的,通过串联各个独立表达式的字符串值(各字符串由特殊变量 SUBSEP 的值隔开)来将逗号隔开的下标转换成为单个字符串上,所以,下面两个索引操作是等同的:
x[expr1,expr2,...exprn]
和
x[expr1SUBSEPexpr2SUBSEP...exprn]
当使用 in 运算符时,一个多维 Index 值应包含在圆括号之中,除了 in 运算符,任何对不存在的数组元素的引用将自动创建该元素。
6.3.2. 运用举例
赋值:
person[person_num, "name"] = "Jack" person[person_num, "age"] = "11" person_num++
上面的代码中,对一个二维数组“person”进行赋值。
6.4. 字段变量
当AWK将一条记录分隔成多个字段后,可以通过 $1、$2 …… 来访问每一个字段($1 表示第一个字段,依次类推)。$0 则表示整个记录。
将一个值指定给不存在的字段(即任何大于$NF字段变量的当前值的字段)将会导致:
- 创建新的字段变量
- 修改NF的值
- 修改$0的值
7. 操作符
7.1. 算术操作符
AWK中支持算术操作符: +(加号)、-(减号),/(除号),^(幂),*(乘号),%(求余)。格式为:
Expression op Expression
7.2. 一元操作符
AWK支持的一元操作符:+ (正号)、-(负号)、++(递增)、--(递减)。
7.3. 赋值操作符
AWK支持的赋值操作符有:=、+=、-=、*=、/=、%=,格式为
Variable op Expression
8. AWK操作
操作在 { } (大括号)中,在括号里可以指定多个操作,但操作间必须以换行字符或分号分隔,且语句以它们出现的顺序处理。操作语句包含:
8.1 条件语句
在AWK中的条件语句的C中的条件语句具有相同的语法和功能。所有语句允许使用 { } (大括号)将语句组合在一起。可以在条件语句的表达式部分和语句部分之间使用可选的换行字符,且换行字符或分号(;)用于隔离{}(大括号)中的多个语句。
8.1.1 遵从C语言规则的条件语句
AWK中共有六种遵从C语言规则的条件语句,分别是:
8.1.1.1 if 语句
if ( Expression ) { Statement } [ else Action ]
如果 Expression 计算结果为真(True),则执行 Statement ,否则,执行 Action (如果有 else 分支的话)。
8.1.1.2 while 语句
while ( Expression ) { Statement }
如果 Expression 的计算结果为真,则执行Statement,然后再次计算 Expression,如果结果为真,则再次执行 Statement,重复这一过程,直到 Expression 的计算结果为假为止。
如果 Expression 的第一次计算结果就为假,则 Statement 永远不会被执行。
8.1.1.3 do - while 语句
do { Statement } while (Expression)
执行 Statement,然后计算 Expression,如果结果为真,则再次执行 Statement,计算 Expression,重复这一过程,直到 Expression 的计算结果为假为止。
如果 Expression 的第一次计算结果就为假,则 Statement 只会被执行一次。
8.1.1.4 for 语句
for ( Expression1 ; Expression2 ; Expression3 ) { Statement }
计算 Expression1,计算 Expression2,如果Expression2计算结果为真,则执行 Statement,然后再执行 Expression3 。重复这一过程(Expression2、Statement、Expression3)直到 Expression2 的计算结果为假为止。
如果 Expression2 的第一次计算结果就为假,则 Statement 和 Expression3 永远不会被执行。
8.1.1.5 break 语句
当break 语句用于 while 或 for 语句时,导致退出循环
8.1.1.6 continue 语句
当 continue 语句用于while 或 for 语句时,导致循环移动到下一个迭代。
上面只对六种语句作了简单介绍,更多内容可以参考C语言的书。
8.1.2 不遵从C语言规则的条件语句
AWK中共有五种不遵从C语言规则的条件语句,分别是:
8.1.2.1 for … in 语句
for ( Variable in Array ) { Statement }
for … in 语句将 Variable 参数设置为 Array 数组变量的每个索引值,一次一个索引且没有特定的顺序,并用第个迭代来执行 Statement 所指定的操作。请参阅 delete 语句以获得 for … in 语句的示例。
8.1.2.2 delete 语句
delete Array [expression]
delete 语句删除数组Array中指定的数组元素和 Expression 参数指定的索引。例如:语句
for ( i in g) delete g[i]
将删除 g[] 数组的每个元素。
8.1.2.3 exit 语句
exit [Expression]
exit 语句首先(按照在AWK文件中出现的先后顺序)调用所有 END 模式的操作,然后以 Expression 参数指定的退出状态终止AWK命令。如果 exit 语句在 END 操作中出现,则不调用后继的 END 操作。
8.1.2.4 next 语句
停止对当前输入记录的处理,从下一个输入记录继续处理。
8.1.2.5 # 语句
在AWK中,注释以 # 开始,一直持续到行结束,类似于C++中的 // 注释。
8.2 输出语句
AWK中提供了两种输出语句:
8.2.1. print
print 的语法格式为:
print [ExpressionList] [Redirection] [Expression]
print 语句将 ExpressionList 参数指定的每个表达式的值写至标准输出,每个表达式由 OFS 特殊变量的当前值隔开,且每个记录由 ORS 特殊变量的当前值终止。
可以使用 Redirection 参数重定向输出,此参数可以使用 > (大于号)、>>(双大于号)和|(管道)进行三种输出重定向。Redirection 参数指定如何重定向输出。
当 Redirection 参数是 > 或 >> 时,Expression 参数是文件的路径名称,如果文件不存在,AWK会自动创建相应的文件。> 表示在写文件时,先清空文件的内容, >> 则表示将内容追加在文件后面。
当 Redirection 参数是 ~| 时,Expression 参数是命令的名称,ExpressionList 的结果将作为命令的输入参数。
注:如果 Expression 参数为 Redirection 参数指定一个路径名称,则 Expression 参数将括在双引号中以确保将它当作字符串对待。
8.2.2. printf
printf 的语法格式为:
printf Format [ExpressionList] [Redirection] [Expression]
printf 语句将 ExpressionList 参数指定的每个表达式的值以 Format 参数指定的格式写至标准输出。 Redirection 和 Expression 参数的作用与 print 语句中相同。
printf 语句中 Format 参数可以使用以下的修饰符(和C语言中的 printf 语句差不多):
修改符 | 含意 |
---|---|
%c | ASCII字符 |
%d | 整数 |
%e | 浮点数,科学记数法 |
%f | 浮点数,如:123.44 |
%g | awk决定使用哪种浮点数转换 e或 f |
%o | 八进制数 |
%x (小写的x) | 十六进制数(A-F部分为小写字母) |
%X(大写的x) | 十六进制数(A-F部分为大写字母) |
9. 内置函数
9.1 算术函数
以下算术函数和C语言中的同名函数操作相同。
函数原型 | 函数说明 |
---|---|
atan2(y, x) | 返回 y/x 的反正切 |
cos(x) | 返回 x 的余弦,x是弧度 |
exp(x) | 返回 x 的幂,e^x |
int(x) | 返回 x 的截断至整数的值 |
log(x) | 返回 x 的自然对数 |
rand() | 返回0 到1 之间任意数字 n, 其中 0 <= n < 1 |
sin(x) | 返回 x 的正弦,x是弧度 |
sqrt(x) | 返回 x 的平方根 |
srand([Expr]) | 将 rand 函数的种子值设置为Expr参数的值,如果省略Expr参数,则使用系统的当前时间。 |
9.2 字符串处理函数
AWK内部提供了一系列处理字符串函数。
函数原型 | 函数说明 |
---|---|
gsub(ere, repl [, in]) | 和sub函数一样,只是会将 in 中所有匹配 ere 的子串都替换为 repl |
index(s, t) | 返回s中字符串 t 第一次出现的位置,0表示字符串 s 中没有子串 t 。 |
length[(s)] | 返回s长度,如果没有参数,则返回 $0 的长度。 |
match(s, ere) | 返回s中第一个匹配扩展正则表达式 ere 的子串的位置。0表示 s 中没有与 ere 匹配的子串。 匹配成功后,特殊变量 RSTART 和 RLENGTH 被设置为匹配成功的子串的位置和长度。 如果没有匹配成功,则设置为 -1 。 |
split(s, a[, fs]) | 以正则表达式 fs 为分隔符,将字符串 s 分隔成字符串数组 a[1]、a[2]、……、a[n]中,并返回 n 的值。 如果没有指定 fs,则使用特殊变量 FS 的值。 |
sprintf(fmt, expr, ...) | 返回经fmt格式化后的expr的字符串 |
sub(ere, repl [, in]) | 将 in 中的第一个匹配扩展正则表达式 ere 的子串替换为 repl 所指定的串。如果 in 没有指定,则使用 $0 。 |
substr(s, m [, n]) | 返回s中,从 m 开始,最大长度为 n 的子串。 如果没有指定n,则返回从m到字符串s结束的子串。 如果 m+n的值大于 s 的长度,则也返回从m到字符串s结束的子串。 |
tolower(s) | 将s中的字符转换成小写字母后返回。(不修改串s的值) |
toupper(s) | 将s中的字符转换成大写字母后返回。(不修改串s的值) |
说明:
1、在AWK中,字符是从 1 开始计数的。所以,index(“01234”, “0”)的返回结果为1。
>> awk 'BEGIN {print index("01234", "0")}' one.unl 1
2、可以直接将字符串值放在一起来实现字符串的连接(类似于C中的strcat函数)。如果想将多个字符串变量连接在一起,记得要使用括号将变量名括起来,这样AWK才能够知道变量的真实名字。如:
first_name = " Benjamin" last_name = " Frnaklin." hello1 = "this is"first_name hello2 = "this is"(first_name)(last_name) # 一定要加括号!
3、在 AWK 中,没有显示的字符串和数字的转换。如果想要将某一个变量 abc 当做数字来进行比较,则应该先使用
abc = abc + 0
来显式地将其转换为数字。
注:在SUN下,如果分隔后的某一个字段中包括了 space,则想直接将其当成数字来和别的数字做比较,会不成功(AWK不会报错,但比较的结果不是想要的结果)。
9.3 其它函数
AWK中的其它函数有:
函数原型 | 函数说明 |
---|---|
close(Expression) | 用同一个带字符串值 的 Expression 参数来关闭由 print 或 printf 语句打开的或调用 getline 函数打开的文件或管道。如果文件或管道成功关闭,则返回0,其它情况,则返回非零值。如果打算写一个文件,并稍后在一个程序中读取该文件,则必须调用 close 。 |
system(cmd) | 执行命令 cmd 并返回其退出状态。 |
Expression ~ | getline [ Variable ] | 从来自 Expression 参数指定的命令的输出中通过管道传送的流中读取一个输入记录,并将该记录的值指定给 Variable 参数指定的变量。 如果当前未打开将 Expression 参数的值作为其命令名称的流,则创建流。创建的流等同于调用 popen 子例程。此时 Command 参数取 Expression 参数的值且 Mode 参数设置为一个是 r 的值。 只要流保留保留打开且 Expression 参数求得同一个字符串,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则$0记录变量和NF特殊变量设置为从流读取的记录。 |
getline [Variable] < Expression | 从Expression参数指定的文件读取输入的下一个记录,并将Variable参数指定的变量设置为该记录的值。只要流保持打开且Expression参数对同一字符串求值,则对getline函数的每次后续调用将读取另一个记录。如果未指定Variable参数,则$0记录变量和NF特殊变量设置为从流读取的记录。 |
getline [Variable] | 将Variable参数指定的变量设置为从当前输入文件读取的下一个输入记录。如果未指定Variable参数,则$0记录变量设置为该记录的值,还将设置NF、NR和FNR特殊变量。 |
注:所有getline函数的格式对于成功输入返回1,对于文件结束返回0,对于错误返回 -1 。
10. 用户自定义函数
用户定义函数以下面的格式说明:
function Name (Parameter, Parameter,...) { Statements }
函数定义可以位于AWK程序中的任何位置,通常是建议放在文件尾(可以参考“AWK运行机制” 一节),甚至可以先使用后定义。函数的作用域是全局的。
函数的参数可以是标题或数组,参数名称对函数而言是本地的,所有其它变量名称都是全局的,同一个名称不应用作不同的实体;例如:一个参数名称不能用作函数名称又用作特殊变量,具有全局作用域的变量不应共享一个函数的名称,同个作用域中的标题和数组不应具有同一个名称。如果参数是标量,则调用时参数是以传值的方式,如果参数是数组,则调用时使用的是以传引用的方式。
函数定义中的参数数量不必和调用函数时使用的参数数量匹配,多余的形式参数可以用作本地变量,额外的标量参数初始化为空字符串(也可以理解为数字值为0(零))。额外的数组参数初始化为空数组。
当调用函数时,函数名称和左括号之间没有空格。函数调用可以是嵌套的或循环的,从任何嵌套的或循环函数调用返回时,所有调用函数的参数的值保持不变,除了引用传送的数组参数,return 语句可用于返回一个值。
在函数定义内,在左大括号({)之前和右大括号(})之后的换行字符是可选的。
下面是一个函数的例子:
function average (g, n) { for (i in g) sum = sum + g[i] avg = sum / n return avg }
将数组 g 和变量 n 以及数组中的元素个数传递给函数 average,然后函数获得一个平均值并返回它。
补充说明
这篇文章是03年某个时候写的,主要是参考AWK的手册及几本Linux书籍整理汇总而成。在工作是仍然用得上,权当AWK便捷手册使用,所以将它收录进来。
声明: 本文采用 CC BY-NC-SA 3.0 协议进行授权,转载请注明出处。