首页 > 代码库 > AWK

AWK

awk提供了许多强大的字符串函数,见下表:
awk内置字符串函数
gsub(r,s)    在整个$0中用s替代r
gsub(r,s,t)    在整个t中用s替代r
index(s,t)    返回s中字符串t的第一位置
length(s)    返回s长度
match(s,r)    测试s是否包含匹配r的字符串
split(s,a,fs)    在fs上将s分成序列a
sprint(fmt,exp)    返回经fmt格式化后的exp
sub(r,s)    用$0中最左边最长的子串代替s
substr(s,p)    返回字符串s中从p开始的后缀部分
substr(s,p,n)    返回字符串s中从p开始长度为n的后缀部分 详细说明一下各个函数的使用方法。

gsub函数有点类似于sed查找和替换。它允许替换一个字符串或字符为另一个字符串或字符,并以正则表达式的形式执行。第一个函数作用于记录$0,第二 个gsub函数允许指定目标,然而,如果未指定目标,缺省为$0。
index(s,t)函数返回目标字符串s中查询字符串t的首位置。length函数返回字符串s字符长度。match函数测试字符串s是否包含一个正则表达式r定义的匹配。split使用域分隔符fs将字符串s划分为指定序列a。sprint函数类似于printf函数(以后涉及),返回基本输出格式fmt的结果字符串exp。sub(r,s)函数将用s替代$0中最左边最长的子串,该子串被(r)匹配。sub(s,p)返回字符串s在位置p后的后缀。substr(s,p,n)同上,并指定子串长度为n。
现在看一看awk中这些字符串函数的功能。

1.gsub
要在整个记录中替换一个字符串为另一个,使用正则表达式格式,/目标模式/,替换模式/。例如改变学生序号4842到4899:

$ awk ‘gsub(/4842/, “4899”) {print $0}‘ grade.txt
J.Troll 07/99 4899 Brown-3 12 26 26

echo "i am hifdafafdst"|awk ‘{gsub(/am/,"abcc",$0);print $0}‘
i abcc hifdafafdst

2.index
查询字符串s中t出现的第一位置。必须用双引号将字符串括起来。例如返回目标字符串Bunny中ny出现的第一位置,即字符个数。

$ awk ‘BEGIN {print index("Bunny", "ny")} grade.txt
4

3.length
返回所需字符串长度,例如检验字符串J.Troll返回名字及其长度,即人名构成的字符个数。

$ awk ‘$1=="J.Troll" {print length($1) " "$1}‘ grade.txt
7 J.Troll

还有一种方法,这里字符串加双引号。

$ awk ‘BEGIN {print length("A FEW GOOD MEN")}‘
14

4.match
match测试目标字符串是否包含查找字符的一部分。可以对查找部分使用正则表达式,返回值为成功出现的字符排列数。如果未找到,返回0,第一个例子在ANCD中查找d。因其不存在,所以返回0。第二个例子在ANCD中查找D。因其存在,所以返回ANCD中D出现的首位置字符数。第三个例子在学生J.Lulu中查找u。

$ awk ‘{BEGIN {print match("ANCD", /d/)}‘
0
$ awk ‘{BEGIN {print match("ANCD", /C/)}‘
3
$ awk ‘$1=="J.Lulu" {print match($1, "u")} grade.txt
4

5.split
使用split返回字符串数组元素个数。工作方式如下:如果有一字符串,包含一指定分隔符-,例如AD2-KP9-JU2-LP-1,将之划分成一个数组。使用split,指定分隔符及数组名。此例中,命令格式为("AD2-KP9-JU2-LP-1",parts_array,"-"),split然后返回数组下标数,这里结果为4。还有一个例子使用不同的分隔符。

$ awk ‘{BEGIN {print split("123#456#678", myarray, "#")}‘
3

这个例子中,split返回数组myarray的下标数。数组myarray取值如下:

Myarray[1]="123"
Myarray[2]="456"
Myarray[3]="789"

6.sub
使用sub发现并替换模式的第一次出现位置。字符串STR包含‘popedpopopill’,执行下列sub命令sub(/op/,"op",STR)。模式op第一次出现时,进行替换操作,返回结果如下:
‘pOPedpopepill’。
假如grade.txt文件中,学生J.Troll的记录有两个值一样,“目前级别分”与“最高级别分”。只改变第一个为29,第二个仍为24不动,操作命令为sub(/26/,"29",$0),只替换第一个出现24的位置。

$ awk ‘$1=="J.Troll" sub(/26/, "29", $0)‘ grade.txt
L.Troll 07/99 4842 Brown-3 12 29 26
L.Transley 05/99 4712 Brown-2 12 30 28

7.substr
substr是一个很有用的函数。它按照起始位置及长度返回字符串的一部分。例子如下:

$ awk ‘$1=="L.Transley" {print substr($1, 1,5)}‘ grade.txt
L.Tan
上面例子中,指定在域1的第一个字符开始,返回其前面5个字符。
如果给定长度值远大于字符串长度, awk将从起始位置返回所有字符,要抽取L.Tansley的姓,只需从第3个字符开始返回长度为7。可以输入长度99,awk返回结果相同。

$ awk ‘{$1=="L.Transley" {print substr($1, 3,99)}‘ grade.txt
Transley

substr的另一种形式是返回字符串后缀或指定位置后面字符。这里需要给出指定字符串及其返回字串的起始位置。例如,从文本文件中抽取姓氏,需操作域 1,并从第三个字符开始:

$ awk ‘{print substr($1, 3)}‘ grade.txt
Troll
Transley

还有一个例子,在BEGIN部分定义字符串,在END部分返回从第t个字符开始抽取的子串。

$ awk ‘{BEGIN STR="A FEW GOOD MEN"} END {print substr(STR,7)) grade.txt
GOOD MEN

8.从shell中向awk传入字符串 
awk脚本大多只有一行,其中很少是字符串表示的,这一点通过将变量传入awk命令行会变得很容易。现就其基本原理讲述一些例子。
使用管道将字符串stand-by传入awk,返回其长度。

$ echo "Stand-by" | awk ‘{print length($0)}‘
8

设置文件名为一变量,管道输出到awk,返回不带扩展名的文件名。

$ STR="mydoc.txt"
$ echo $STR | awk ‘{print subst($STR, 1, 5)}‘
mydoc

设置文件名为一变量,管道输出到awk,只返回其扩展名。
$ STR="mydoc.txt"
$ echo $STR | awk ‘{print substr($STR, 7)}‘
txt

1.print函数  
例子1:  
$ date  
2005年04月30日 星期六 19时29分25秒 CST  
$ date|awk ‘{print "Date:" $1 "\nTime:" $3}‘  
Date:2005年04月30日  
Time:19时34分24秒  
注意,用date命令查看时间格式。不同的语言可能格式也不一样,因此 awk也要随之而变\n是转义序列,表示换行符。常见转义序列如下表:  转义序列用一个反斜杠后跟一个字母或者数字表示
转义序列
含义
\b
退格
\f
换页
\n
换行
\t
制表符(空格)
\r
回车
例子2:  
$ awk ‘/Sally/{print "\t\tHave a nice day, "$1,$2 "\!"}‘ employees  
Have a nice day, Sally Chang!  
解释:如果包含模式Sally,则print函数打印两个跳格,串Have a nice day,第一个字段和第二个字段,然后跟叹号。  
2.  在一个文件里的awk命令  
如果awk命令放在文件里,就使用-f选项和awk文件名结合使用。处理过程: 把一条记录读到awk的缓存里而且对该记录测试并执行awk文件里的每个命令。在awk完成对第一记录的操作后,删除该记录并把下一条记录读入缓存,依此类推。如果操作不受模式控制,则默认行为是打印整个记录。  
例子:  
$ cat employees  
Tom Jones 4424 5/12/66 543354  
Mary Adams 5346 11/4/63 28765  
Sally Chang 1654 7/22/54 650000  
Billy Black 1683 9/23/44 336500  
$ cat awkfile  
/^Mary/{print "Hello Mary!"}  
{print $1, $2, $3}  
$ awk -f awkfile employees  
Tom Jones 4424  
Hello Mary!  
Mary Adams 5346  
Sally Chang 1654  
Billy Black 1683  
3. 记录和字段  
1〉记录:awk不把输入数据看作一个无穷的字符串,而是把它看作一种格式 或结构。默认情况下把每行叫做一个记录(record),并以一个换行符终 止。输入和输出的记录分隔符默是回车符,保存在内置awk变量ORS 和RS中。ORS和RS可以改变,但是方式有限。  
例子:  
$ awk ‘{print $0}‘ employees  
Tom Jones 4424 5/12/66 543354  
Mary Adams 5346 11/4/63 28765  
Sally Chang 1654 7/22/54 650000  
Billy Black 1683 9/23/44 336500  
解释:变量$0保存当前记录,这条命令相当于awk ‘{print}‘ employees  
例子:  
$ awk ‘{print NR,$0}‘ employees  
1 Tom Jones 4424 5/12/66 543354  
2 Mary Adams 5346 11/4/63 28765  
3 Sally Chang 1654 7/22/54 650000  
4 Billy Black 1683 9/23/44 336500  
解释:NR代表行号。  
4字段  
类似表中的字段,是指记录中的一个词条。默认字段分隔符是空白区字段, 也就是空格或制表符(TAB)。Awk中用NF来记录每条记录的字段数量。  
字段分隔符  
输入字段分隔符:awk的内置变量FS保存输入字段分隔符的值。当时用FS 的默认值时,awk用空格或制表符分隔字段,删除前导空白区和制表符。FS 可以改变,可以在BEGIN语句中改变,也可以在命令中改变。要想在命 令中改变需要用-F选项。  
举例:  
$ cat employees2  
Tom Jones:4424:5/12/66:543354  
Mary Adams:5346:11/4/63:28765  
Sally Chang:1654:7/22/54:650000  
Billy Black:1683:9/23/44:336500  
$ awk ‘{print $1,$2}‘ employees2  
Tom Jones:4424:5/12/66:543354  
Mary Adams:5346:11/4/63:28765  
Sally Chang:1654:7/22/54:650000  
Billy Black:1683:9/23/44:336500  
$ awk -F: ‘{print $1,$2}‘ employees2  
Tom Jones 4424  
Mary Adams 5346  
Sally Chang 1654  
Billy Black 1683  
举例2:多个字段分隔符。如果使用多个字段分隔符,要将其封装在方括号里。  
$ awk -F‘[ :\t]‘ ‘{print $1,$2,$3}‘ employees2  
Tom Jones 4424  
Mary Adams 5346  
Sally Chang 1654  
Billy Black 1683  
解释:把空格、制表符、冒号当成输入字段分隔符。
输出字段分隔符:默认的输出字段分隔符用逗号来分隔,被分隔的字段之间打 印一个空格,如果字段之间没有逗号,则打印时各字段将挤在一起。  
5.模式和操作  
awk 模式(patterns)控制awk将对一行输入作什么样的操作。一个模式包括 一个正则表达式,一个产生正确或者错误条件的表达式,或者它们的组合。 默认操作时打印模式中符合表达式条件的各行。当读入一个模式时,有一条 隐含的if语句。如果if语句是隐含的,周围可以没有花括号。  
例子:  
$ awk ‘$37/22/54 650000  
Billy Black 1683 9/23/44 336500  
解释:如果第3个字段小于4000,则打印该字段。  
操作:操作(actions)是封装在花括号里且由分号分隔的语句。如果一个模式 在一个操作之前,则该模式规定了何时执行该操作。  
举例:  
$ awk ‘/Tom/{print "Hello there," $1}‘ employees  
Hello there,Tom  
解释:如果记录中包含Tom,则打印Hello there,Tom  
6.正则表达式  
一个正则表达式对awk来说是一个由封装在正斜杠里的字符组成的模式。Awk 支持的正则表达式与egrep基本一样,可以参考下表
元字符
说明
^
字符串首
$
字符串尾
.
单个任意字符
*
零个或者多个前导字符
+
一个或者多个前导字符
?
零个或者一个前导字符
[ABC]
匹配【】中的任一字符
[^ABC]
匹配任何一个不在【】中的字符
[A-Z]
匹配A-Z之间的任一字符
A|B
A或者B
(AB)+
一个或者多个AB组合
\*
*本身
&
替代符,替代查找串中匹配的内容
举例:  
$ awk ‘/^Mary/‘ employees  
Mary Adams 5346 11/4/63 28765  
解释:显示employees文件中以Mary开头的行  
$ awk ‘/^[A-Z][a-z]* /‘ employees  
Tom Jones 4424 5/12/66 543354  
Mary Adams 5346 11/4/63 28765  
Sally Chang 1654 7/22/54 650000  
Billy Black 1683 9/23/44 336500  
解释:显示行开头是一个大写字母,然后跟一个或多个小写字母,再跟一个
空格。  
匹配操作符(~)、否定号(!)用来与以条记录或字段里的表达式相匹配。  
例子:  
$ awk ‘$1 ~/[Bb]ill/‘ employees  
Billy Black 1683 9/23/44 336500  
解释:awk将显示第一个字段里与Bill或者bill相匹配的行  
$ awk ‘$1 !~/ly$/‘ employees  
Tom Jones 4424 5/12/66 543354  
Mary Adams 5346 11/4/63 28765  
解释:显示第一个字段中末尾不是ly的所有行。  
比较表达式比较行,如果行里的条件为真,就执行操作。如果给表达式求值 为真则值等于1,反之等于0。  
7.关系操作符  
下表列出了关系操作符。  
运算符
含义
示例

小于
x
小于等于
x
==
等于
x==y
!=
不等于
x!=y
>=
大于等于
x>=y
>
大于
x>y
~
与正则表达式匹配
X~/y/
!~
不与正则表达式匹配
x!~/y/
关系操作符举例:  
$ cat employees  
Tom Jones 4423 5/12/66 543354  
Mary Adams 5346 11/4/63 28765  
Sally Chang 1654 7/22/54 650000  
Billy Black 1683 9/23/44 336500  
$ awk ‘$3==4423‘ employees  
Tom Jones 4423 5/12/66 543354  
$ awk ‘$3 >;5000{print $1}‘ employees  
Mary  
$ awk ‘$2 !~/Adam/‘ employees  
Tom Jones 4423 5/12/66 543354  
Sally Chang 1654 7/22/54 650000  
Billy Black 1683 9/23/44 336500  
条件表达式:一个条件表达式用两个符号,问号和冒号来给表达式求值。  
8.条件表达式  
格式:  
conditional expression1?expression2:expression3  它等同于
{if(expression1)  
expression2  
else  
expression3  
}  
条件表达式举例:  
awk ‘{max=($1>;$2)?$1:$2;print max}‘ employees 
解释:如果第一个字段大于第二个字段,就把第一个字段的内容赋给max,反之把第
二个字段的内容赋给max,然后打印max  
9.计算  
可以在模式里执行计算。awk以浮点方式执行所有的算术运算。
+  加  
-  减  
* 乘  
/ 除  
10.复合模式  
复合模式 (compound patterns) 是把模式和逻辑操作符相结合的表达式,给 一个表达式从左到右求值。  
                              逻辑运算符
运算符
含义
例子
&&
逻辑与
A&&B
||
逻辑或
A||B
!
逻辑非
!A
复合模式举例:  
$ awk ‘$3>;4000 && $35/12/66 543354  
Mary Adams 5346 11/4/63 28765  
$ awk ‘!($3>;4000 && $311.范围模式  
范围模式从一个模式的第一次出现匹配到第二个模式的第一次出现,然后从 第一个模式的第二次出现匹配到第二个模式的第二次出现等等。如果第一个 模式被匹配,而第二个模式没有找到,则awk将显示直到末尾的所有行。  
例子:  
$ cat datafile  
northwest NW Joel Craig 3.0 .98 3 4  
western WE Sharon Kelly 5.3 .97 5 23  
southwest SW Chris Foster 2.7 .8 2 18  
southern SO May Chin 5.1 .95 4 15  
southeast SE Derek Johnson 4.0 .7 4 17  
eastern EA Susan Beal 4.4 .84 5 20  
northeast NE TJ Nichols 5.1 .94 3 13  
north NO Val Shultz 4.5 .89 5 9  
central CT Sheri Watson 5.7 .94 5 13  
$ awk ‘/^north/,/^west/‘ datafile  
northwest NW Joel Craig 3.0 .98 3 4  
western WE Sharon Kelly 5.3 .97 5 23  
northeast NE TJ Nichols 5.1 .94 3 13  
north NO Val Shultz 4.5 .89 5 9  
central CT Sheri Watson 5.7 .94 5 13  
12.变量  
内置变量要大写,他们可以用在表达式里而且可以被重置。如下表  
变量名
含义
ARGC
命令行参数的数目
FILENAME
当前输入文件的的文件名
FNR
当前文件的记录数
FS
输入字段分隔符,默认为空格
NF
当前记录中的字段数
NR
目前的记录数
OFS
输出字段分隔符
ORS
输出记录分隔符
RS
输入记录分隔符
IGNORECASE
在正则表达式和字符串匹配中不区分大小写(值为非0时)
内置变量举例:  
$ awk -F: ‘$1=="Mary Adams"{print NR,$1,$2,$NF}‘ employees2  
2 Mary Adams 5346 28765  
解释:-F选项把分隔符改成冒号。如果字段1等于Mary Adams,则打印记 录号、第一个字段、第二个字段和最后一个字段($NF)  
赋值运算符
运算符
含义
等效表达式
=
A=5
A=5
+=
A=a+5
A+=5
-=
A=a-5
a-=5
*=
A=a*5
A*=5
/=
A=a/5
a/=5

 

AWK