/Linux/Unix中awk命令教程和awk示例
在本文中,我们将学习在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 '{printid 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示例显示了BEGIN
和END
块的用法:
# 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,}' /tmp/userdata.txt 2 1 hynman 31 hynman# awk 'NR % 2 == 1{ print NR,}' /tmp/userdata.txt 2 1 hynman 31 hynman 4 3 Amit 33 amit 6 4 Sumit 33 sumit# awk 'NR==2, NR==4 { print NR,}' /tmp/userdata.txt 1 id Name Age username 3 2 Rahul 32 rahul 5# awk '/hynman/,/amit/{ print NR,}' /tmp/userdata.txt 2 1 hynman 31 hynman 3 2 Rahul 32 rahul 4 3 Amit 33 amit# awk ' ~ /a/{print NR,}' /tmp/userdata.txt 2 1 hynman 31 hynman 3 2 Rahul 32 rahul 4 3 Amit 33 amit# awk ' ~ /^A/{print NR,} ' /tmp/userdata.txt 1 id Name Age username 2 1 hynman 31 hynman 3 2 Rahul 32 rahul# awk ' ~ /^[AD]/{print NR,} ' /tmp/userdata.txt 4 3 Amit 33 amit# awk ' ~ /k$/{print NR,} ' /tmp/userdata.txt 2 1 hynman 31 hynman 4 3 Amit 33 amit# awk ' >= 32 {print NR,} ' /tmp/userdata.txt 2 1 hynman 31 hynman# awk ' == "hynman" {print NR,} ' /tmp/userdata.txt 1 id Name Age username 3 2 Rahul 32 rahul 4 3 Amit 33 amit 6 4 Sumit 33 sumit# awk ' >= 30 && <= 32 {print NR,} ' /tmp/userdata.txt 2 1 hynman 31 hynman# /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
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.通过数字比较进行打印选择
我们可以使用关系运算符(==,> =,<=,>,<,!=
)执行数字比较。
其中:我们执行一个大于或者等于(> =
)的数字,以在第三个字段中打印值等于或者大于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脚本示例文件的可执行权限
##代码##执行脚本
##代码##