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 |