首页 > 代码库 > awk简单实用功能

awk简单实用功能

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中同时提供了printprintf两种打印输出的函数,其中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基本相似。下面我们给出awkprintf的格式化说明符列表:

格式化说明符

功能

示例

结果

%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中默认的记录分隔符是回车,保存在其内建变量ORSRS中。$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

 

匹配操作符:

" ~ " 用来在记录或者域内匹配正则表达式。

#显示所有第一个域匹配Billbill的行。

[root@shell test]# awk ‘$1 ~ /[Bb]ill/‘ testfile

Billy Black       1683    9/23/44         336500

 

#显示所有第一个域不匹配Billbill的行,其中!~表示不匹配的意思。

[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

 

#打印所有以sono开头的行。

[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