/Linux/Unix中awk命令教程和awk示例

时间:2020-01-09 10:37:16  来源:igfitidea点击:

在本文中,我们将学习在Linux和Unix中使用的AWK命令。

在Linux或者Unix中,什么是AWK?

AWK是一种解释型编程语言,旨在用于文本处理和报告生成。
它通常用于数据操作,例如在大多数类Unix操作系统中搜索数据中的项,执行算术运算以及重组原始数据以生成报告。

awk中的程序与大多数其他语言中的程序不同,因为awk程序是数据驱动的(即,我们描述要使用的数据,然后在找到数据时要执行的操作)。

当我们运行awk时,可以指定一个awk程序来告诉awk该怎么做。
该程序包含一系列规则。
从语法上讲,规则由一个模式和一个动作组成。
该动作用大括号括起来,以将其与模式分开。

AWK的类型

AWK语言最初是在Unix上作为AWK实用程序实现的。
如今,大多数Linux发行版都提供ANU的GNU实现(GAWK),并且AWK的符号链接是从原始GAWK二进制文件创建的。

  • AWK

  • NAWK

  • GAWK

AWK命令语法,用于操作和模式结构

AWK程序是一个或者多个模式的序列,后跟动作语句。
这些操作模式语句用换行符分隔。
操作(AWK命令)和模式(搜索模式)都是可选的,因此我们使用{}来区分它们:下面是操作和模式结构的awk命令语法:

/search pattern/{ action/awk-commands }/search pattern/{ action/awk-commands }

仅模式语句的AWK命令语法

仅带模式的awk命令语法如下:

awk   '/pattern /'    inputfilename

在给定的awk命令示例中,处理了passwd文件的所有行,并打印了包含邮件模式的行:

# awk '/mail/' /tmp/passwd
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

仅操作语句的AWK命令语法

仅带有操作的awk命令语法如下:

awk '{ action statements/awk-commands }' inputfilenames

在给定的awk命令示例中,所有员工姓名均在屏幕上以awk打印列打印为$ 2,代表每条输入行的第二列。

# awk '{print }' /tmp/userdata.txt
Name
hynman
Rahul
Amit
Sumit

1.打印每个输入行或者记录的AWK示例

我们可以通过多种方式打印输入文件的每个输入记录。
让我们看一些更多的awk示例。

# awk '//' /tmp/userdata.txt
# awk '{print}' /tmp/userdata.txt
# awk '{print 
id   Name    Age  username
1    hynman  31   hynman
2    Rahul   32   rahul
3    Amit    33   amit
4    Sumit   33   sumit
}' /tmp/userdata.txt # awk '//{print}' /tmp/userdata.txt

通过打印输入文件/tmp/userdata.txt的所有输入记录,所有给定的awk命令示例都将产生相同的结果。

# awk 'BEGIN { print "==Employee Info==" }  	          <-- begin block 
> { print }						  <-- body block 
> END { print "==ends here==" }' /tmp/userdata.txt	  <-- end block
==Employee Info==
id   Name    Age  username
1    hynman  31   hynman
2    Rahul   32   rahul
3    Amit    33   amit
4    Sumit   33   sumit
==ends here==

2.使用BEGIN和END块构造

AWK包含两个特殊关键字" BEGIN"和" END",用于需要采取措施的模式。
它们都是可选的,并且不带斜线使用。
它们与任何输入行都不匹配。

下面的awk示例显示了BEGINEND块的用法:

# cat cmd.awk
BEGIN { print "=== Emp Info ===" }
{ print }

3.从源文件运行awk

当AWK程序较长时,将它们放在单独的文件中会更方便。
将AWK程序放在文件中可以减少错误和重新键入。

-f选项告诉AWK实用程序从source_file读取AWK命令。
任何文件名都可以代替source_file使用。
让我们来看一些awk示例,我们可以创建一个包含AWK命令的awk脚本示例" cmd.awk"文本文件,如下所示:

# awk -f cmd.awk userdata.txt
=== Emp Info ===
id   Name    Age  username
1    hynman  31   hynman
2    Rahul   32   rahul
3    Amit    33   amit
4    Sumit   33   sumit

现在,我们指示AWK从cmd.awk文件中读取命令并执行给定的操作:

# cat cmd.awk
# awk script Examples for AWK Tutorial
#!/bin/awk -f
BEGIN { print "=== Emp Info ===" }
{ print }

4.用于编程的AWK脚本示例

我们可以编写独立的AWK脚本来执行AWK命令,就像使用shell脚本来执行Shell命令一样。
我们使用#来创建AWK脚本,其后是AWK解释器的绝对路径和-f可选参数。

以下是一个小awk脚本示例:

# chmod u+x /tmp/cmd.awk

授予此awk脚本示例文件可执行文件权限

# ./cmd.awk userdata.txt
=== Emp Info ===
id   Name    Age  username
1    hynman  31   hynman
2    Rahul   32   rahul
3    Amit    33   amit
4    Sumit   33   sumit

接下来,只需在shell上运行./cmd.awk userdata.txt,系统便会运行AWK,就像我们键入awk -f cmd.awk userdata.txt一样:

# cat cmd.awk
# awk script Examples for AWK Tutorial
#!/bin/awk -f
# Info        : This program displays the employees information
# Date        : 22 Jan 2017
# Version     : 1.0
# This is BEGIN block comment
BEGIN { print "=== Emp Info ===" }
# Body block comment
{ print }
# End block comment
END { print "=== Information Database ends here ===" }

5. AWK中的评论

注释是程序中包含的一些用于文档或者人工信息的文本。
它不是程序的可执行部分。
它说明了程序的功能以及如何执行。
我们将创建带有一些注释的awk脚本示例。

让我们看一些awk脚本示例,我们可以将以下内容放在cmd.awk中:

# ./cmd.awk userdata.txt
=== Emp Info ===
id   Name    Age  username
1    hynman  31   hynman
2    Rahul   32   rahul
3    Amit    33   amit
4    Sumit   33   sumit
=== Information Database ends here ===

接下来执行awk脚本示例脚本,这是输出:

# awk '/rahul/' /tmp/userdata.txt
2    Rahul   32   rahul

6. AWK匹配模式,无需操作声明即可打印

在这个awk示例中,程序有一个模式,但是我们没有指定任何动作语句。

# awk '{ print ,  }' /tmp/userdata.txt
id Name
1 hynman
2 Rahul
3 Amit
4 Sumit

在这种情况下,AWK仅选择其中包含" rahul"模式/字符串的输入行。
当我们不指定任何动作时,AWK会假定该动作是打印整行。

7. AWK打印列,不指定任何模式

在这个awk示例中,我们将不包括任何模式,而是使用awk打印列。
给定的AWK命令打印每行以空格(输出字段分隔符,用逗号表示)分隔的输入行的第一列($ 1)和第二列($ 2):

# awk '/hynman/{ print  "\t"  "\t" }' /tmp/userdata.txt
1       hynman  31

8.具有匹配模式的AWK打印列

在这个awk示例中,我们将同时包含动作和模式以及awk打印列。
给定的AWK命令将打印由选项卡(指定\ t为输出分隔符)分隔的第一列($ 1),第二行($ 2)和第三列($ 3)包含他们中的hynman字符串:

# awk '{ print  " is mapped to "  ", with age "  ", and username "  }' /tmp/userdata.txt
id is mapped to Name, with age Age, and username username
1 is mapped to hynman, with age 31, and username hynman
2 is mapped to Rahul, with age 32, and username rahul
3 is mapped to Amit, with age 33, and username amit
4 is mapped to Sumit, with age 33, and username sumit

9.带有自定义文本的任意顺序的AWK打印列

在这个awk示例中,用awk打印列的顺序不同。
其中:在动作语句中,我们在行内容之间放置了一些文本

# awk '/hynman/{ print  " is mapped to "  ", with age "  ", and username "  }' /tmp/userdata.txt
1 is mapped to hynman, with age 31, and username hynman

我们还可以为操作添加一个模式匹配,然后使用awk打印列。
其中:我们搜索hynman字符串,然后使用来自不同列的值打印文本。

# awk '{ print NF, , $NF }' /tmp/userdata.txt
4 id username
4 1 hynman
4 2 rahul
4 3 amit
4 4 sumit

10.打印一行中的列数

AWK具有内置变量来计数和存储当前输入行中的字段数,例如NF。
因此,在给定的awk示例中,我们将打印每条输入行的列数,然后打印第一列和最后一列(可通过NF访问):

# awk '{ print " No of fields: " NF ", and the last field contains "$NF }' /tmp/userdata.txt
 No of fields: 4, and the last field contains username
 No of fields: 4, and the last field contains hynman
 No of fields: 4, and the last field contains rahul
 No of fields: 4, and the last field contains amit
 No of fields: 4, and the last field contains sumit

由于我们有4列,所以NF打印4,并且由于我们要打印$ NF的变量值为4,因此awk会打印第四列的内容

我们可以将文本放在字段之间,然后awk打印列

# awk '//' /tmp/userdata.txt
id   Name    Age  username
1    hynman  31   hynman
2    Rahul   32   rahul
3    Amit    33   amit
4    Sumit   33   sumit

11.使用NF删除空行

我们可以使用NF> 0来打印至少1个字段的所有行。
这是使用AWK从文件中删除空行的最简单方法:其中:我在第三行后的输入文件中添加了空行

# awk 'NF > 0 { print }' /tmp/userdata.txt
id   Name    Age  username
1    hynman  31   hynman
2    Rahul   32   rahul
3    Amit    33   amit
4    Sumit   33   sumit

使用带有NF的awk删除空行

# awk '{ print NR, 
# awk ' END { print "The total number of lines in file are : " NR } ' /tmp/userdata.txt
The total number of lines in file are : 6
}' /tmp/userdata.txt 1 id Name Age username 2 1 hynman 31 hynman 3 2 Rahul 32 rahul 4 3 Amit 33 amit 5 6 4 Sumit 33 sumit

12.在输出中打印行号

AWK具有一个称为NR的内置变量。
它计算到目前为止读取的输入行数。
我们可以在打印语句中使用NR前缀$ 0来显示已处理的每一行的行号:

# awk  'NR==2 { print NR, 
# awk  'NR % 2 == 0{ print NR, 
# awk  'NR % 2 == 1{ print NR, 
# awk  'NR==2, NR==4 { print NR, 
# awk '/hynman/,/amit/{ print NR, 
# awk '  ~ /a/{print NR, 
# awk '  ~ /^A/{print NR, 
# awk '  ~ /^[AD]/{print NR, 
# awk '  ~ /k$/{print NR, 
# awk '  >= 32 {print NR, 
# awk '  == "hynman" {print NR, 
# awk '  >= 30 &&  <= 32  {print NR, 
# /tmp/header.awk /tmp/userdata.txt
Field1 Field2 Field3 Field4
id     Name    Age   username
1      hynman  31    hynman
2      Rahul   32    rahul
3      Amit    33    amit
4      Sumit   33    sumit
} ' /tmp/userdata.txt 2 1 hynman 31 hynman 3 2 Rahul 32 rahul
} ' /tmp/userdata.txt 2 1 hynman 31 hynman
} ' /tmp/userdata.txt 1 id Name Age username 3 2 Rahul 32 rahul 4 3 Amit 33 amit 6 4 Sumit 33 sumit
} ' /tmp/userdata.txt 2 1 hynman 31 hynman
} ' /tmp/userdata.txt 2 1 hynman 31 hynman 4 3 Amit 33 amit
} ' /tmp/userdata.txt 4 3 Amit 33 amit
} ' /tmp/userdata.txt 1 id Name Age username 2 1 hynman 31 hynman 3 2 Rahul 32 rahul
}' /tmp/userdata.txt 2 1 hynman 31 hynman 3 2 Rahul 32 rahul 4 3 Amit 33 amit
}' /tmp/userdata.txt 2 1 hynman 31 hynman 3 2 Rahul 32 rahul 4 3 Amit 33 amit
}' /tmp/userdata.txt 1 id Name Age username 3 2 Rahul 32 rahul 5
}' /tmp/userdata.txt 2 1 hynman 31 hynman 4 3 Amit 33 amit 6 4 Sumit 33 sumit
}' /tmp/userdata.txt 2 1 hynman 31 hynman

13.通过使用NR计算文件中的行数来获得AWK sum列

在我们的下一个awk示例中,我们将使用NR计数文件中的行数,并使用awk sum列。
由于NR存储了当前输入行号,因此我们需要处理awk sum列文件中的所有行。
我们也不想打印每行的行号,因为我们的要求是只求awk sum列。
由于END块是在处理完输入行之后执行的,因此我们将在END块中打印NR以使用awk sum列打印文件中的总行数:

# awk '{ last = 
# awk 'END { print "Total no of lines in file: ", NR}' /tmp/userdata.txt
Total no of lines in file:  6
} END { print last }' /tmp/userdata.txt 4 Sumit 33 sumit

14.仅从文件中打印编号的行

我们知道NR包含当前输入行的行号。
我们可以通过将行号与NR中存储的当前输入行号进行匹配,轻松地有选择地打印任何行,如以下awk示例所示:

# awk '{print length, 
# awk 'BEGIN { FS = ":"} {print }' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
}' /tmp/passwd 31 root:x:0:0:root:/root:/bin/bash 32 bin:x:1:1:bin:/bin:/sbin/nologin 39 daemon:x:2:2:daemon:/sbin:/sbin/nologin 36 adm:x:3:4:adm:/var/adm:/sbin/nologin 40 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 31 sync:x:5:0:sync:/sbin:/bin/sync 44 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 32 halt:x:7:0:halt:/sbin:/sbin/halt 46 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

15.文件中带有偶数行的AWK打印行

使用NR,我们可以通过在模式空间中指定表达式(将每行号除以2并找到余数)来轻松打印偶数文件,如以下awk示例所示:

# awk 'BEGIN{ n=1; while (n < 5 ) { print n; n++; } }'
1
2
3
4

16.文件中带有奇数行的AWK打印行

同样,通过在模式空间中执行基本的算术运算,我们可以在带有awk打印列的NR中使用NR列出文件中的奇数行:

# cat /tmp/while1.awk
# awk script Examples for AWK Tutorial
#!/bin/awk -f
BEGIN { n=1
while ( n < 5 )
 {
  print n;
  n++;
  }
}

17.使用范围运算符(,)和NR的AWK打印行

我们可以结合使用范围运算符()和NR来基于文件的行号从文件中打印出一组行。
下一个awk示例显示" userdata.txt"文件中的第2至第4行:

# chmod u+x /tmp/while1.awk

18.使用范围运算符和样式的AWK打印行

我们还可以在模式空间中结合使用范围运算符()和字符串,以从文件中的第一个模式开始直到第二个模式打印一组行。

# /tmp/while1.awk
1
2
3
4

19.使用匹配运算符(~)进行打印选择

匹配运算符(~)用于匹配文件输入行中指定字段中的模式。
在下一个awk示例中,我们将在输入行的第二栏中选择并打印所有包含'a'的行,如下所示:

##代码##

20.使用匹配运算符(~)和锚点(^)进行打印选择

正则表达式(也称为锚)中的插入符号(^)用于在行的开头进行匹配。
在下一个awk示例中,我们将其与匹配运算符(~)组合以打印第二个字段以"`A"字符开头的所有行,如下

##代码##

21.使用匹配运算符(~)和字符类([])选择打印

正则表达式中的字符类[]用于匹配方括号中指定的单个字符。
其中:我们将匹配运算符(~)与字符类(/^ [AD] /)相结合,以打印第二个字段以'A'或者'D'字符开头的所有行,如下所示:

##代码##

22.使用匹配运算符(~)和锚点($)进行打印选择:

正则表达式(也称为锚点)中的美元符号($)用于在行尾匹配。
在下一个awk示例中,我们将其与匹配运算符(~)相结合,以使用'k`字符打印第二个字段末尾的所有行,如下所示:

##代码##

23.通过数字比较进行打印选择

我们可以使用关系运算符(==,> =,&lt;=,>,&lt;,!=)执行数字比较。
其中:我们执行一个大于或者等于(> =)的数字,以在第三个字段中打印值等于或者大于32的行,如下所示:

##代码##

24.通过字段中的文本内容/字符串匹配进行打印选择

除了数字匹配,我们还可以使用字符串匹配来查找字段中包含特定字符串的行。
匹配的字符串内容应以双引号作为字符串给出

在我们的下一个awk示例中,我们在第四字段($ 4)中打印所有包含hynman的行,如下所示:

##代码##

25.通过组合图案进行打印选择

我们可以将模式与括号和逻辑运算符&&||和`!其中:我们打印的行在第三字段中的值大于或者等于30,在第三字段中的值小于或者等于32.

##代码##

26.使用AWK BEGIN打印标题

AWK BEGIN块可用于打印标题,初始化变量,执行计算或者在AWK开始处理输入文件中的行之前要执行的任何其他任务。

##代码##

27.使用AWK END打印最后一条输入行

在最后一个文件的最后一行的处理完成之后,执行AWK END块,并且$ 0存储每个处理过的输入行的值,但是它的值不保留在END块中。
以下是打印最后输入行的一种方法:

##代码##

为了打印文件中的总行数,我们使用NR,因为它在END块中保留其值,如下所示:

##代码##

28.使用长度功能计算字符数

默认情况下,长度函数存储输入行中字符数的计数。
在下一个示例中,我们将使用length函数为每行添加字符数作为前缀,如下所示:

##代码##

29.使用FS更改字段分隔符

到目前为止,我们已经讨论过的awk示例中的字段由空格字符分隔。
FS的默认行为是任意数量的空格或者制表符。
我们可以使用FS变量或者-F选项将其更改为正则表达式或者任何单个或者多个字符。

在此,我们使用Linux的/etc/passwd文件,该文件用冒号()分隔字段。
因此,在从文件中读取任何数据之前,我们将FS的输入更改为冒号,并打印存储在文件第一字段中的用户名列表,如下所示:

##代码##

30.控制结构(示例:AWK while循环)

AWK支持控制(流)语句,该语句可用于更改AWK程序中命令的执行顺序。
AWK支持不同的构造,例如if ... else,while和for控制结构。
另外,break和continue语句与控制结构结合使用以修改命令的执行顺序。

让我们尝试一个while循环的基本示例,以打印5以下的数字列表:

##代码##

或者,我们也可以创建awk脚本示例

##代码##

提供对awk脚本示例文件的可执行权限

##代码##

执行脚本

##代码##