awk实用功能:
(来自网友Stephen Liu)
和sed一样,awk也是逐行扫描文件的,从第一行到最后一行,寻找匹配特定模板的行,并在这些行上运行“选择”动作。如果一个模板没有指定动作,这些匹配的行就被显示在屏幕上。如果一个动作没有模板,所有被动作指定的行都被处理。
awk的基本格式:
/> awk ‘pattern‘ filename
/> awk ‘{action}‘ filename
/> awk ‘pattern {action}‘ filename
[root@shell test]# cat testfile
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
#打印所有包含模板Mary的行
[root@shell test]# awk ‘/Mary/‘ testfile
Mary Adams 5346 11/4/63 28765
#打印文件中的第一个字段,这个域在每一行的开始,缺省由空格或其它分隔符。
[root@shell test]# awk ‘{print $1}‘ testfile
Tom
Mary
Sally
Billy
#打印包含模板Sally的行的第一、第二个域字段
[root@shell test]# awk ‘/Sally/{print $1,$2}‘ testfile
Sally Chang
awk的格式输出:
awk中同时提供了print和printf两种打印输出的函数,其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。下面给出基本的转码序列:
转码 | 含义 |
\n | 换行 |
\r | 回车 |
\t | 制表符 |
#输出年和月,用\n换行符
[root@shell test]# date
2014年 06月 13日 星期五 17:29:23 CST
[root@shell test]# date | awk ‘{print "Month: " $2 "\nYear: ", $1}‘
Month: 06月
Year: 2014年
#这里用到了\t制表符
root@shell test]# awk ‘/Sally/{print "\t\tHave a nice day, " $1,$2 "\!"}‘ testfile
awk: 警告: 转义序列“\!”被当作单纯的“!”
Have a nice day, Sally Chang!
在打印数字的时候你也许想控制数字的格式,我们通常用printf来完成这个功能。awk的特殊变量OFMT也可以在使用print函数的时候,控制数字的打印格式。它的默认值是"%.6g"----小数点后面6位将被打印。
[root@shell test]# awk ‘BEGIN { OFMT="%.2f"; print 1.2456789, 12E-2}‘
1.25 0.12
现在我们介绍一下功能更为强大的printf函数,其用法和c语言中printf基本相似。下面我们给出awk中printf的格式化说明符列表:
格式化说明符 | 功能 | 示例 | 结果 |
%c | 打印单个ASCII字符。 | printf("The character is %c.\n",x) | The character is A. |
%d | 打印十进制数。 | printf("The boy is %d years old.\n",y) | The boy is 15 years old. |
%e | 打印用科学记数法表示的数。 | printf("z is %e.\n",z) | z is 2.3e+01. |
%f | 打印浮点数。 | printf("z is %f.\n",z) | z is 2.300000 |
%o | 打印八进制数。 | printf("y is %o.\n",y) | y is 17. |
%s | 打印字符串。 | printf("The name of the culprit is %s.\n",$1); | The name of the culprit is Bob Smith. |
%x | 打印十六进制数。 | printf("y is %x.\n",y) | y is f. |
注:假设列表中的变脸值为x = A, y = 15, z = 2.3, $1 = "Bob Smith"
# %-15s表示保留15个字符的空间,同时左对齐
[root@shell test]# echo "Linux" | awk ‘{printf "|%-15s|\n", $1}‘
|Linux |
# %-15s表示保留15个字符的空间,同时右对齐
[root@shell test]# echo "Linux" | awk ‘{printf "|%15s|\n", $1}‘
| Linux|
#%8d表示数字右对齐,保留8个字符的空间。
[root@shell test]# awk ‘{printf "The name is %-15s ID is %8d\n", $1,$3}‘ testfile
The name is Tom ID is 4424
The name is Mary ID is 5346
The name is Sally ID is 1654
The name is Billy ID is 1683
awk中的记录和域:
awk中默认的记录分隔符是回车,保存在其内建变量ORS和RS中。$0变量是指整条记录。
#这等同于print的默认行为
[root@shell test]# awk ‘{print $0}‘ testfile
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
#变量NR(Number of Record),记录每条记录的编号。
[root@shell test]# awk ‘{print NR, $0}‘ testfile
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
# 变量NF(Number of Field),记录当前记录有多少域
[root@shell test]# awk ‘{print $0,NF}‘ testfile
Tom Jones 4424 5/12/66 543354 5
Mary Adams 5346 11/4/63 28765 5
Sally Chang 1654 7/22/54 650000 5
Billy Black 1683 9/23/44 336500 5
#根据employees生成employees2。
[root@shell test]# sed ‘s/[[:space:]]\+\([0-9]\)/:\1/g;w employees‘ testfile
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
[root@shell test]# 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
#这里-F选项后面的字符表示分隔符。
[root@shell test]# awk -F: ‘/Tom Jones/{print $1,$2}‘ employees
Tom Jones 4424
变量OFS(Output Field Seperator)表示输出字段间的分隔符,缺省是空格。
#在输出时,域字段间的分隔符已经是?(问号)了
[root@shell test]# awk -F: ‘{OFS = "?"};/Tom/{print $1,$2 }‘ employees
Tom Jones?4424
对于awk而言,其模式部分将控制这动作部分的输入,只有符合模式条件的记录才可以交由动作部分基础处理,而模式部分不仅可以写成正则表达式(如上面的例子),awk还支持条件表达式,如:
[root@shell test]# awk ‘$3 < 4000 {print}‘ testfile
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
模式和动作一般是捆绑在一起的。需要注意的是,动作是花括号内的语句。模式控制的动作是从第一个左花括号开始到第一个右花括号结束,如下:
[root@shell test]# awk ‘$3 < 4000 && /Sally/ {print}‘ testfile
Sally Chang 1654 7/22/54 650000
匹配操作符:
" ~ " 用来在记录或者域内匹配正则表达式。
#显示所有第一个域匹配Bill或bill的行。
[root@shell test]# awk ‘$1 ~ /[Bb]ill/‘ testfile
Billy Black 1683 9/23/44 336500
#显示所有第一个域不匹配Bill或bill的行,其中!~表示不匹配的意思。
[root@shell test]# awk ‘$1 !~ /[Bb]ill/‘ testfile
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
awk的基本应用实例:
[root@shell test]# cat testfile.txt
northwest NW Charles Main 3.0 .98 3 34
western WE Sharon Gray 5.3 .97 5 23
southwest SW Lewis Dalsass 2.7 .8 2 18
southern SO Suan Chin 5.1 .95 4 15
southeast SE Patricia Hemenway 4.0 .7 4 17
eastern EA TB Savage 4.4 .84 5 20
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9
central CT Ann Stephens 5.7 .94 5 13
#打印所有以north开头的行
[root@shell test]# awk ‘/^north/‘ testfile.txt
northwest NW Charles Main 3.0 .98 3 34
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9
#打印所有以so和no开头的行。
[root@shell test]# awk ‘/^(no|so)/‘ testfile.txt
northwest NW Charles Main 3.0 .98 3 34
southwest SW Lewis Dalsass 2.7 .8 2 18
southern SO Suan Chin 5.1 .95 4 15
southeast SE Patricia Hemenway 4.0 .7 4 17
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9
#第五个域字段匹配包含.(点),后面是7-9的数字。
[root@shell test]# awk ‘$5 ~ /\.[7-9]+/‘ testfile.txt
southwest SW Lewis Dalsass 2.7 .8 2 18
central CT Ann Stephens 5.7 .94 5 13
#第八个域以两个数字结束的打印。
[root@shell test]# awk ‘$8 ~ /[0-9][0-9]$/{print $8}‘ testfile.txt
34
23
18
15
17
20
13
awk表达式功能:
比较表达式:
比较表达式匹配那些只在条件为真时才运行的行。这些表达式利用关系运算符来比较数字和字符串。见如下awk支持的条件表达式列表:
运算符 | 含义 | 例子 |
< | 小于 | x < y |
<= | 小于等于 | x <= y |
== | 等于 | x == y |
!= | 不等于 | x != y |
>= | 大于等于 | x >= y |
> | 大于 | x > y |
~ | 匹配 | x ~ /y/ |
!~ | 不匹配 | x !~ /y/ |
[root@shell test]# cat testfile
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
#打印第三个域等于5346的行。
[root@shell test]# awk ‘$3==5346‘ testfile
Mary Adams 5346 11/4/63 28765
#打印第三个域大于5000的行的第一个域字段。
[root@shell test]# awk ‘$3>5000 {print $1}‘ testfile
Mary
#打印第二个域匹配Adam的行
[root@shell test]# awk ‘$2 ~ /Adam/‘ testfile
Mary Adams 5346 11/4/63 28765
条件表达式:
条件表达式使用两个符号--问号和冒号给表达式赋值: conditional expression1 ? expression2 : expressional3,其逻辑等同于C语言中的条件表达式。其对应的if/else语句如下:
{
if (expression1)
expression2
else
expression3
}
root@shell test]# cat testfile.txt
northwest NW Charles Main 3.0 .98 3 34
western WE Sharon Gray 5.3 .97 5 23
southwest SW Lewis Dalsass 2.7 .8 2 18
southern SO Suan Chin 5.1 .95 4 15
southeast SE Patricia Hemenway 4.0 .7 4 17
eastern EA TB Savage 4.4 .84 5 20
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9
central CT Ann Stephens 5.7 .94 5 13
#取前三行第七个字段,如果第7个字段大于4则输出为high第七字段,其他的为low第七字段
[root@shell test]# awk ‘NR <= 3 {print ($7 > 4 ? "high "$7 : "low "$7) }‘ testfile.txt
low 3
high 5
low 2
数学表达式:
运算可以在模式内进行,其中awk将所有的运算都视为浮点运算,见如下列表:
运算符 | 含义 | 例子 |
+ | 加 | x + y |
- | 减 | x - y |
* | 乘 | x * y |
/ | 除 | x / y |
% | 取余 | x % y |
^ | 乘方 | x ^ y |
#如果记录包含正则表达式southern,第五个域就加10并打印。
[root@shell test]# awk ‘/southern/ {print $5+10}‘ testfile.txt
15.1
#如果记录包含正则表达式southern,第八个域除以2并打印。
[root@shell test]# awk ‘/southern/ {print $8/2}‘ testfile.txt
7.5
逻辑表达式:
见如下列表:
运算符 | 含义 | 例子 |
&& | 逻辑与 | a && b |
|| | 逻辑或 | a || b |
! | 逻辑非 | !a |
#打印出第八个域的值大于10小于17的记录。
[root@shell test]# awk ‘$8>10 && $8<17‘ testfile.txt
southern SO Suan Chin 5.1 .95 4 15
central CT Ann Stephens 5.7 .94 5 13
#打印第二个域等于NW,或者第一个域匹配south的行的第一、第二个域。
[root@shell test]# awk ‘$2 == "NW" || $1 ~ /south/ {print $1,$2}‘ testfile.txt
northwest NW
southwest SW
southern SO
southeast SE
#打印第八个域字段不大于13的行的第八个域。
[root@shell test]# awk ‘!($8 > 13) {print $8}‘ testfile.txt
3
9
13
范围模板:
范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现,第一个模板的下一次出现到第一个模板的下一次出现等等。如果第一个模板匹配而第二个模板没有出现,awk就显示到文件末尾的所有行。
#打印以western开头到eastern开头的记录的第一个域
[root@shell test]# awk ‘/^western/,/^eastern/ {print $1}‘ testfile.txt
western
southwest
southern
southeast
eastern
赋值符号:
#找到第三个域等于Ann的记录,然后给该域重新赋值为Christian,之后再打印输出该记录。
[root@shell test]# awk ‘$3 == "Ann" { $3 = "Christian"; print}‘ testfile.txt
central CT Christian Stephens 5.7 .94 5 13
#找到包含Ann的记录,并将该条记录的第八个域的值+=12,最后再打印输出。
[root@shell test]# awk ‘/Ann/{$8 += 12; print $8}‘ testfile.txt
25
本文出自 “Chocolee” 博客,请务必保留此出处http://chocolee.blog.51cto.com/8158455/1426963
原文地址:http://chocolee.blog.51cto.com/8158455/1426963