gawk进阶
Posted tianmu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gawk进阶相关的知识,希望对你有一定的参考价值。
#使用变量 一、内建变量 1. 字段和记录分隔符变量 gawk数据字段和记录变量 变 量 描 述 FIELDWIDTHS 由空格分隔的一列数字,定义了每个数据字段确切宽度 FS 输入字段分隔符 RS 输入记录分隔符 OFS 输出字段分隔符 ORS 输出记录分隔符 FS与OPS的使用 $ cat data1 data11,data12,data13,data14,data15 data21,data22,data23,data24,data25 data31,data32,data33,data34,data35 $ gawk ‘BEGINFS="," print $1,$2,$3‘ data1 -- 默认情况下,gawk将 OFS 设成一个空格 data11 data12 data13 data21 data22 data23 data31 data32 data33 $ gawk ‘BEGINFS=","; OFS="-" print $1,$2,$3‘ data1 -- 修改输出分隔符值 data11-data12-data13 data21-data22-data23 data31-data32-data33 FIELDWIDTHS 变量定义了四个字段,根据已定义好的字段长度来分割 $ cat data1b 1005.3247596.37 115-2.349194.00 05810.1298100.1 $ gawk ‘BEGINFIELDWIDTHS="3 5 2 5"print $1,$2,$3,$4‘ data1b 100 5.324 75 96.37 115 -2.34 91 94.00 058 10.12 98 100.1 RS与ORS的使用:默认情况下,gawk将 RS 和 ORS 设为换行符 $ cat data2 Riley Mullen 123 Main Street Chicago, IL 60601 (312)555-1234 Frank Williams 456 Oak Street Indianapolis, IN 46201 (317)555-9876 Haley Snell 4231 Elm Street Detroit, MI 48201 (313)555-4938 $ gawk ‘BEGINFS="\n"; RS="" print $1,$4‘ data2 -- 现在gawk把文件中的每行都当成一个字段,把空白行当作记录分隔符 Riley Mullen (312)555-1234 Frank Williams (317)555-9876 Haley Snell (313)555-4938 2. 数据变量 更多的gawk内建变量 变 量 描 述 ARGC 当前命令行参数个数 ARGIND 当前文件在 ARGV 中的位置 ARGV 包含命令行参数的数组 CONVFMT 数字的转换格式(参见 printf 语句),默认值为 %.6 g ENVIRON 当前shell环境变量及其值组成的关联数组 ERRNO 当读取或关闭输入文件发生错误时的系统错误号 FILENAME 用作gawk输入数据的数据文件的文件名 FNR 当前数据文件中的数据行数 IGNORECASE 设成非零值时,忽略 gawk 命令中出现的字符串的字符大小写 NF 数据文件中的字段总数 NR 已处理的输入记录数 OFMT 数字的输出格式,默认值为 %.6 g RLENGTH 由 match 函数所匹配的子字符串的长度 RSTART 由 match 函数所匹配的子字符串的起始位置 ARGC与ARGV $ gawk ‘BEGINprint ARGC,ARGV[1]‘ data1 -- ARGC 变量表明命令行上有两个参数。 ARGV 数组从索引 0 开始。 ENVIRON 变量,使用关联数组来提取shell环境变量 $ gawk ‘ > BEGIN > print ENVIRON["HOME"] > print ENVIRON["PATH"] > ‘ /home/rich /usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin NF 变量可以让你在不知道具体位置的情况下指定记录中的最后一个数据字段 $ gawk ‘BEGINFS=":"; OFS=":" print $1,$NF‘ /etc/passwd -- rich:/bin/bash testy:/bin/csh mark:/bin/bash dan:/bin/bash mike:/bin/bash test:/bin/bash FNR 和 NR 变量虽然类似,但又略有不同。 $ gawk ‘ > BEGIN FS="," > print $1,"FNR="FNR,"NR="NR > ENDprint "There were",NR,"records processed"‘ data1 data1 data11 FNR=1 NR=1 data21 FNR=2 NR=2 data31 FNR=3 NR=3 data11 FNR=1 NR=4 -- FNR 变量的值在 gawk 处理第二个数据文件时被重置了,而 NR 变量则在处理第二个数据文件时继续计数。 data21 FNR=2 NR=5 data31 FNR=3 NR=6 There were 6 records processed 2 data1 二、自定义变量 gawk自定义变量名可以是任意数目的字母、数字和下划线,但不能以数字开头。注意: gawk 变量名区分大小写! 1. 在脚本中给变量赋值(值可以是数字、文本,赋值支持数学算式) $ gawk ‘ > BEGIN > testing="This is a test" > print testing > testing=45 > print testing > ‘ This is a test 45 $ gawk ‘BEGINx=4; x= x * 2 + 3; print x‘ 11 2. 在命令行上给变量赋值 $ cat script1 BEGINFS="," print $n $ gawk -f script1 n=2 data1 -- 显示了文件的第二个数据字段 data12 data22 data32 用 -v 命令行参数,它允许你在 BEGIN 代码之前设定变量,否则设定的变量值在begin部分不可用。-v 命令行参数必须放在脚本代码之前。 $ gawk -v n=3 -f script2 data1 The starting value is 3 data13 data23 data33 #处理数组 定义数组变量 格式:var[index] = element 其中 var 是变量名,index 是关联数组的索引值,element 是数据元素值 $ gawk ‘BEGIN > capital["Illinois"] = "Springfield" > print capital["Illinois"] > ‘ Springfield $ $ gawk ‘BEGIN > var[1] = 34 > var[2] = 3 > total = var[1] + var[2] > print total > ‘ 37 遍历数组变量 gwak遍历格式: for (var in array) statements 变量中存储的是索引值而不是数组元素值 $ gawk ‘BEGIN > var["a"] = 1 > var["g"] = 2 > var["m"] = 3 > var["u"] = 4 > for (test in var) > > print "Index:",test," - Value:",var[test] > > ‘ Index: u - Value: 4 Index: m - Value: 3 Index: a - Value: 1 Index: g - Value: 2 删除数组变量 格式:delete array[index] 删除命令会从数组中删除关联索引值和相关的数据元素值 $ gawk ‘BEGIN > var["a"] = 1 > var["g"] = 2 > for (test in var) > > print "Index:",test," - Value:",var[test] > > delete var["g"] > print "---" > for (test in var) > print "Index:",test," - Value:",var[test] > ‘ Index: a - Value: 1 Index: g - Value: 2 --- Index: a - Value: 1 #使用模式 正则表达式 正则表达式必须出现在它要控制的程序脚本的左花括号前 $ gawk ‘BEGINFS="," /11/print $1‘ data1 data11 匹配操作符 匹配操作符是波浪线( ~ ),允许将正则表达式限定在记录中的特定数据字段 $ gawk –F: ‘$1 !~ /rich/print $1,$NF‘ /etc/passwd -- gawk程序脚本会打印/etc/passwd文件中与用户ID rich 不匹配的用户ID和登录shell root /bin/bash daemon /bin/sh bin /bin/sh sys /bin/sh $ gawk -F: ‘$1 ~ /rich/print $1,$NF‘ /etc/passwd rich /bin/bash $ gawk ‘BEGINFS="," $2 ~ /^data2/print $0‘ data1 data21,data22,data23,data24,data25 数学表达式 可以使用任何常见的数学比较表达式。 x == y :值x等于y。 x <= y :值x小于等于y。 x < y :值x小于y。 x >= y :值x大于等于y。 x > y :值x大于y。 $ gawk -F: ‘$4 == 0print $1‘ /etc/passwd -- 显示所有属于root用户组(组ID为 0 )的系统用户 root sync shutdown halt operator 也可以对文本数据使用表达式,跟正则表达式不同,表达式必须完全匹配 $ gawk -F, ‘$1 == "data"print $1‘ data1 $ $ gawk -F, ‘$1 == "data11"print $1‘ data1 data11 #结构命令 if语句 gawk编程语言支持标准的 if-then-else 格式的 if 语句。你必须为 if 语句定义一个求值的条件,并将其用圆括号括起来 格式:if (condition) statement1 $ cat data4 10 5 13 50 34 $ gawk ‘if ($1 > 20) print $1‘ data4 50 34 $ gawk ‘ > if ($1 > 20) > -- 执行多条语句,就必须用花括号将它们括起来 > x = $1 * 2 > print x > > ‘ data4 100 68 gawk 的 if 语句也支持 else 子句,允许在 if 语句条件不成立的情况下执行一条或多条语句 $ gawk ‘ > if ($1 > 20) > > x = $1 * 2 > print x > else > > x = $1 / 2 > print x > ‘ data4 5 2.5 6.5 100 68 while语句 while 循环允许遍历一组数据,并检查迭代的结束条件 格式: while (condition) statements $ cat data5 130 120 135 160 113 140 145 170 215 $ gawk ‘ > total = 0 > i = 1 > while (i < 4) > > total += $i > i++ > > avg = total / 3 > print "Average:",avg > ‘ data5 Average: 128.333 Average: 137.667 Average: 176.667 gawk编程语言支持在 while 循环中使用 break 语句和 continue 语句,允许你从循环中跳出 $ gawk ‘ > total = 0 > i = 1 > while (i < 4) > > total += $i > if (i == 2) > break > i++ > > avg = total / 2 > print "The average of the first two data elements is:",avg > ‘ data5 The average of the first two data elements is: 125 The average of the first two data elements is: 136.5 The average of the first two data elements is: 157.5 do—while语句 do-while 语句类似于 while 语句,但会在检查条件语句之前执行命令 格式: do statements while (condition) $ gawk ‘ > total = 0 > i = 1 > do > > total += $i > i++ > while (total < 150) > print total ‘ data5 250 160 315 for语句 gawk编程语言支持C风格的 for 循环 格式:for( variable assignment; condition; iteration process) $ gawk ‘ > total = 0 > for (i = 1; i < 4; i++) > > total += $i > > avg = total / 3 > print "Average:",avg > ‘ data5 Average: 128.333 Average: 137.667 Average: 176.667 #格式化打印 格式:printf "format string", var1, var2 . . . format string 是格式化输出的关键它会用文本元素和格式化指定符来具体指定如何呈现格式化输出。格式化指定符是一种特殊的代码,会指明显示什么类型的变量以及如何显示。gawk程序会将每个格式化指定符作为占位符,供命令中的变量使用。第一个格式化指定符对应列出的第一个变量,第二个对应第二个变量,依此类推 格式化指定符格式:%[modifier]control-letter -- 其中 control-letter 是一个单字符代码,用于指明显示什么类型的数据 格式化指定符的控制字母 控制字母 描 述 c 将一个数作为ASCII字符显示 d 显示一个整数值 i 显示一个整数值(跟d一样) e 用科学计数法显示一个数 f 显示一个浮点值 g 用科学计数法或浮点数显示(选择较短的格式) o 显示一个八进制值 s 显示一个文本字符串 x 显示一个十六进制值 X 显示一个十六进制值,但用大写字母A~F 科学计数法显示一个数 $ gawk ‘BEGIN > x = 10 * 100 > printf "The answer is: %e\n", x > ‘ The answer is: 1.000000e+03 除了控制字母外,还有3种修饰符可以用来进一步控制输出: width :指定了输出字段最小宽度的数字值。如果输出短于这个值, printf 会将文本右对齐,并用空格进行填充。如果输出比指定的宽度还要长,则按照实际的长度输出。 prec :这是一个数字值,指定了浮点数中小数点后面位数,或者文本字符串中显示的最大字符数。 - (减号):指明在向格式化空间中放入数据时采用左对齐而不是右对齐。在使用 printf 语句时,你可以完全控制输出样式 通过添加一个值为 16 的修饰符,我们强制第一个字符串的输出宽度为16个字符。默认情况下,printf 命令使用右对齐来将数据放到格式化空间中。要改成左对齐,只需给修饰符加一个减号即可 $ gawk ‘BEGINFS="\n"; RS="" printf "%-16s %s\n", $1, $4‘ data2 Riley Mullen (312)555-1234 Frank Williams (317)555-9876 Haley Snell (313)555-4938 #内建函数 数学函数 gawk数学函数 函 数 描 述 atan2(x, y) x/y的反正切,x和y以弧度为单位 cos(x) x的余弦,x以弧度为单位 exp(x) x的指数函数 int(x) x的整数部分,取靠近零一侧的值 log(x) x的自然对数 rand( ) 比0大比1小的随机浮点值 sin(x) x的正弦,x以弧度为单位 sqrt(x) x的平方根 srand(x) 为计算随机数指定一个种子值 gawk还支持一些按位操作数据的函数。 and(v1, v2) :执行值 v1 和 v2 的按位与运算。 compl(val) :执行 val 的补运算。 lshift(val, count) :将值 val 左移 count 位。 or(v1, v2) :执行值 v1 和 v2 的按位或运算。 rshift(val, count) :将值 val 右移 count 位。 xor(v1, v2) :执行值 v1 和 v2 的按位异或运算。 字符串函数 gawk字符串函数 函 数 描 述 asort(s [,d]) 将数组s按数据元素值排序。索引值会被替换成表示新的排序顺序的连续数字。另外,如果指定了d,则排序后的数组会存储在数组d中 asorti(s [,d]) 将数组s按索引值排序。生成的数组会将索引值作为数据元素值,用连续数字索引来表明排序顺序。另外如果指定了d,排序后的数组会存储在数组d中 gensub(r, s, h [, t]) 查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r。如果h是一个以g或G开头的字符串,就用s替换掉匹配的文本。如果h是一个数字,它表示要替换掉第h处r匹配的地方 gsub(r, s [,t]) 查找变量$0或目标字符串t(如果提供了的话)来匹配正则表达式r。如果找到了,就全部替换成字符串s index(s, t) 返回字符串t在字符串s中的索引值,如果没找到的话返回 0 length([s]) 返回字符串s的长度;如果没有指定的话,返回$0的长度 match(s, r [,a]) 返回字符串s中正则表达式r出现位置的索引。如果指定了数组a,它会存储s中匹配正则表达式的那部分 split(s, a [,r]) 将s用 FS 字符或正则表达式r(如果指定了的话)分开放到数组a中。返回字段的总数 sprintf(format,variables) 用提供的format和variables返回一个类似于printf输出的字符串 sub(r, s [,t]) 在变量$0或目标字符串t中查找正则表达式r的匹配。如果找到了,就用字符串s替换掉第一处匹配 substr(s, i [,n]) 返回s中从索引值i开始的n个字符组成的子字符串。如果未提供n,则返回s剩下的部分 tolower(s) 将s中的所有字符转换成小写 toupper(s) 将s中的所有字符转换成大写 转换大写,返回长度 $ gawk ‘BEGINx = "testing"; print toupper(x); print length(x) ‘ TESTING 7 排序 $ gawk ‘BEGIN > var["a"] = 1 > var["g"] = 2 > var["m"] = 3 > var["u"] = 4 > asort(var, test) > for (i in test) > print "Index:",i," - value:",test[i] > ‘ Index: 4 - value: 4 Index: 1 - value: 1 Index: 2 - value: 2 Index: 3 - value: 3 时间函数 gawk的时间函数 函 数 描 述 mktime(datespec) 将一个按YYYY MM DD HH MM SS [DST]格式指定的日期转换成时间戳值 ① strftime(format[,timestamp]) 将当前时间的时间戳或timestamp(如果提供了的话)转化格式化日期(采用shell函数date()的格式) systime( ) 返回当前时间的时间戳 例如: $ gawk ‘BEGIN > date = systime() > day = strftime("%A, %B %d, %Y", date) > print day > ‘ Friday, December 26, 2014 #自定义函数 定义函数 格式: function name([variables]) statements 使用自定义函数 在定义函数时,它必须出现在所有代码块之前(包括 BEGIN 代码块),有助于将函数代码与gawk程序的其他部分分开 $ gawk ‘ > function myprint() > > printf "%-16s - %s\n", $1, $4 > > BEGINFS="\n"; RS="" > > myprint() > ‘ data2 Riley Mullen - (312)555-1234 Frank Williams - (317)555-9876 Haley Snell - (313)555-4938 创建函数库 $ cat funclib function myprint() printf "%-16s - %s\n", $1, $4 function myrand(limit) return int(limit * rand()) function printthird() print $3 $ cat script4 BEGIN FS="\n"; RS="" myprint() $ gawk -f funclib -f script4 data2 Riley Mullen - (312)555-1234 Frank Williams - (317)555-9876 Haley Snell - (313)555-4938 #实例 计算保龄球锦标赛成绩 $ cat scores.txt Rich Blum,team1,100,115,95 Barbara Blum,team1,110,115,100 Christine Bresnahan,team2,120,115,118 Tim Bresnahan,team2,125,112,116 $ cat bowling.sh for team in $(gawk –F, ‘print $2‘ scores.txt | uniq) do gawk –v team=$team ‘BEGINFS=","; total=0 if ($2==team) total += $3 + $4 + $5; END avg = total / 6; print "Total for", team, "is", total, ",the average is",avg ‘ scores.txt done $ sh bowling.sh Total for team1 is 635, the average is 105.833 Total for team2 is 706, the average is 117.667
以上是关于gawk进阶的主要内容,如果未能解决你的问题,请参考以下文章
《Linux命令行与shell脚本编程大全》第二十二章 gawk进阶
我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情