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

很不巧,上面我们的数据非常规整,长度都大于40且长度一样。

打印文件的偶数行

[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

我这里没有指定要打印数据, 默认是打印$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

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

,    {    ?    :    ||    &&    do    else

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