1 简介

1.0 关于awk语言

awk的基本功能是搜索包含特定模式的行(或其他文本单元)的文件。当一行符合其中一个模式时,awk将在该行上执行指定的操作。 awk继续以这种方式处理输入行,直到达到输入文件的末尾。

awk中的程序与大多数其他语言中的程序不同,因为awk程序是数据驱动的(即,描述要使用的数据,然后在找到它时执行什么操作)。大多数其他语言是程序性的;你必须详细描述程序应该采取的每一步。在使用程序语言时,通常要更清楚地描述程序将要处理的数据。出于这个原因,awk程序通常很容易读写。

当你运行awk时,你指定了一个awk程序来告诉awk该怎么做。该程序由一系列规则组成(它也可能包含函数定义,我们现在将忽略的高级功能;请参阅用户定义)。每个规则指定一个要搜索的模式和一个寻找模式的操作。

在语法上,一个规则由一个模式和一个动作组成。这个动作用大括号括起来以便将它从模式中分离出来。换行通常分开规则。因此,一个awk程序看起来像这样:

pattern { action }
pattern { action }
…

1.1 如何运行awk

运行一个简单的awk是这个样子的

awk 'program' input-file1 input-file2 …

1.1.1 运行awk没有输入文件

如果这是一个简单的打印工作,不需要输入,我们可以使用如下方式:

[root@centos74 test]$ awk 'BEGIN {print "hello world"}'
hello world

1.1.2 运行一个长命令

我们如果代码过于长的话, 可以考虑把代码写入到文件中去,可以参考如下用法:

[root@centos74 test]$ vim advice.awk
[root@centos74 test]$ cat advice.awk
BEGIN { print "hellow world 2" }
[root@centos74 test]$ awk -f advice.awk
hellow world 2

1.1.3 执行awk脚本文件

上面的awk脚本已经写入到文件了,但是不是太完善, 我们可以改下为如下:

[root@centos74 test]$ cp advice.awk advice2.awk
[root@centos74 test]$ vim advice2.awk
[root@centos74 test]$ cat advice2.awk
#!/usr/bin/awk -f
BEGIN { print "hellow world 3" }
[root@centos74 test]$ chmod a+x advice2.awk
[root@centos74 test]$ ./advice2.awk
hellow world 3

Note

上面的`#!/usr/bin/awk -f` 是Shebang机制,正如写bash脚本需要加`#!/usr/bin/bash`一样的

1.1.4 在awk脚本中添加注释

添加注释和bash一样。 需要在行首添加一个#即可

[root@centos74 test]$ cp advice2.awk  advice3.awk
[root@centos74 test]$ vim advice3.awk
[root@centos74 test]$ cat advice3.awk
#!/usr/bin/awk -f
# this is a  test script
BEGIN { print "hellow world 3" } # this is a comment
[root@centos74 test]$ ./advice3.awk
hellow world 3

Warning

这个再次强调下,“# this is test script”是注释,第一行虽然也是“#”打头,但不是注释。是Shebang机制要求的。

1.1.5 shell下的引号问题

awk的`progra`语句用单引号引起来,里面用到字符串使用双引号引起来。

[root@centos74 test]$ awk 'BEGIN { print "this is a quote" }'
this is a quote

如果内部用到的字符串使用了单引号,可以采取如下措施:

[root@centos74 test]$ awk -v sq="'" 'BEGIN { print "Here is a single quote <" sq ">" }'
Here is a single quote <'>

上面使用了一个变量sq来表示单引号,里面引用这个变量就可以了。避免了各种转义引起的繁琐问题。

1.2 样例数据

为了后续的实验方便,这里提供几个样例文件:

[root@centos74 test]$ cat mail-list
Amelia       555-5553     amelia.zodiacusque@gmail.com    F
Anthony      555-3412     anthony.asserturo@hotmail.com   A
Becky        555-7685     becky.algebrarum@gmail.com      A
Bill         555-1675     bill.drowning@hotmail.com       A
Broderick    555-0542     broderick.aliquotiens@yahoo.com R
Camilla      555-2912     camilla.infusarum@skynet.be     R
Fabius       555-1234     fabius.undevicesimus@ucb.edu    F
Julie        555-6699     julie.perscrutabor@skeeve.com   F
Martin       555-6480     martin.codicibus@hotmail.com    A
Samuel       555-3430     samuel.lanceolis@shu.edu        A
Jean-Paul    555-2127     jeanpaul.campanorum@nyu.edu     R
[root@centos74 test]$ cat inventory-shipped
Jan  13  25  15 115
Feb  15  32  24 226
Mar  15  24  34 228
Apr  31  52  63 420
May  16  34  29 208
Jun  31  42  75 492
Jul  24  34  67 436
Aug  15  34  47 316
Sep  13  55  37 277
Oct  29  54  68 525
Nov  20  87  82 577
Dec  17  35  61 401

Jan  21  36  64 620
Feb  26  58  80 652
Mar  24  75  70 495
Apr  21  70  74 514

1.3 一些简单的awk使用

找到mail-list文件中,包含了li字符串的行

[root@centos74 test]$ awk '/li/ {print $0}' mail-list
Amelia       555-5553     amelia.zodiacusque@gmail.com    F
Broderick    555-0542     broderick.aliquotiens@yahoo.com R
Julie        555-6699     julie.perscrutabor@skeeve.com   F
Samuel       555-3430     samuel.lanceolis@shu.edu        A

“/li/”是个正则表达式,默认是匹配行的,如果行满足就执行后面{}里面的代码。

找到行长度大于40的行,并显示长度

[root@centos74 test]$ awk 'length($0) > 40 { print length($0) , $0} ' mail-list
59 Amelia       555-5553     amelia.zodiacusque@gmail.com    F
59 Anthony      555-3412     anthony.asserturo@hotmail.com   A
59 Becky        555-7685     becky.algebrarum@gmail.com      A
59 Bill         555-1675     bill.drowning@hotmail.com       A
59 Broderick    555-0542     broderick.aliquotiens@yahoo.com R
59 Camilla      555-2912     camilla.infusarum@skynet.be     R
59 Fabius       555-1234     fabius.undevicesimus@ucb.edu    F
59 Julie        555-6699     julie.perscrutabor@skeeve.com   F
59 Martin       555-6480     martin.codicibus@hotmail.com    A
59 Samuel       555-3430     samuel.lanceolis@shu.edu        A
59 Jean-Paul    555-2127     jeanpaul.campanorum@nyu.edu     R

length是awk内置的函数,计算字符串的长度的。

打印文件的偶数行

[root@centos74 test]$ awk 'NR % 2 == 0' mail-list
Anthony      555-3412     anthony.asserturo@hotmail.com   A
Bill         555-1675     bill.drowning@hotmail.com       A
Camilla      555-2912     camilla.infusarum@skynet.be     R
Julie        555-6699     julie.perscrutabor@skeeve.com   F
Samuel       555-3430     samuel.lanceolis@shu.edu        A

NR是awk内置的变量,用于代表当前处理的记录数(现在你就暂且理解为当前处理的行号吧)我这里没有指定要打印数据, 默认是打印$0,也就是整行数据

1.4 两个规则样例

上面的样例,我们都使用的单一个条件匹配就打印了。 如果条件比较复杂就需要多个条件来控制了。

[root@centos74 test]$ awk '/12/ {print $0 }
> /21/  {print $0 } ' mail-list inventory-shipped
Anthony      555-3412     anthony.asserturo@hotmail.com   A
Camilla      555-2912     camilla.infusarum@skynet.be     R
Fabius       555-1234     fabius.undevicesimus@ucb.edu    F
Jean-Paul    555-2127     jeanpaul.campanorum@nyu.edu     R
Jean-Paul    555-2127     jeanpaul.campanorum@nyu.edu     R
Jan  21  36  64 620
Apr  21  70  74 514

写了2组,每组都是一个pattern,一个打印, 如果满足就打印。

1.5 关于awk语句的跨行问题

跨行问题很常见的,一行写不完就需要写2行甚至多行。

[root@centos74 test]$ awk 'BEGIN{print "this is a test,this is a test , this is a test \
> this is a test " }'
this is a test,this is a test , this is a test this is a test

Attention

对于普通的字符串需要换行的时候,我们需要添加``去转义回车符号。 但是对于如下字符我们没有必要去添加转义符号:

,    {    ?    :    ||    &&    do    else

上面的字符我们没有必要去添加转义符号, 还有一些awk内置的关键词也是如此。如果一行写不下。直接回车写下一行就是了。