Linux awk命令
awk
References:
Awk Tutorial - Tutorialspoint.
30 Examples for Awk Command in Text Processing - Like Geeks.
Awk Command in Linux with Examples | Linuxize(强烈推荐,把awk命令介绍得明明白白).
初识awk
什么是awk
AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯、彼得·溫伯格和布萊恩·柯林漢姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK提供了极其强大的功能:可以进行正则表达式的匹配,样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上AWK的确拥有自己的语言:AWK程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”。它允许创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。gawk是AWK的GNU版本。
最简单地说,AWK是一种用于处理文本的编程语言工具。AWK在很多方面类似于Unix shell编程语言,尽管AWK具有完全属于其本身的语法。它的设计思想来源于SNOBOL4、sed、Marc Rochkind设计的有效性语言、语言工具yacc和lex,当然还从C语言中获取了一些优秀的思想。在最初创造AWK时,其目的是用于文本处理,并且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。
将维基百科awk介绍进行简明概括就是:awk是一种用于文本处理的语言,通过编写符合awk语言的脚本表达式或文件后,交给awk来处理输入文件。
"awk"有两种意思:
- awk指的是用于文本处理的脚本语言。
- awk是用于文本处理的实用程序(属于Utility或者Tool)。
awk作为程序时,会使用awk语言编写的脚本文件作为处理规则,将处理规则运用到输入文件上。在我们探讨awk脚本设计时,就像你学c语言一样,它也应该有它的程序设计规则。
awk脚本的特性
30 Examples for Awk Command in Text Processing - Like Geeks:
The awk command or GNU awk in specific provides a scripting language for text processing. With awk scripting language, you can make the following:
- Define variables.
- Use string and arithmetic operators.
- Use control flow and loops.
- Generate formatted reports.
awk的用途
列操作、数据的统计
awk用于处理何种信息?awk主要用于处理文本,多用于日志文件。
awk处理方式:排除信息、查询信息、统计信息、替换信息(并不是真正地写入到原文件,而是处理结果的替换)
awk工作流程
awk的执行流程图(来源于Awk Tutorial - Tutorialspoint):
awk命令语法格式
awk命令用于执行awk脚本文件,为了让awk脚本正确执行,调用awk命令时应该符合下面两种语法格式:
一种是awk脚本写在命令行上的语法格式:
1 | awk [OPTIONS...] [PROGRAM] INPUT_FILE |
[OPTIONS…] - 选项(参数)
[PROGRAM] - awk语言脚本表达式的集合。
INPUT_FILE - 要处理的输入文件
一种是awk脚本写在文件中的语法格式:
1 | awk [OPTIONS...] -f PROGRAM_FILE INPUT_FILE |
PROGRAM_FILE - 编写awk语言脚本表达式的文件
awk脚本设计
在外文上经常会出现这两个属于"awk script"和"awk program",它们指的都是用awk语言写的程序。下面是awk脚本设计的英文参考,如果不想细看,可以看中文部分。
Awk Command in Linux with Examples | Linuxize:
To process a text with
awk
, you write a program that tells the command what to do. The program consists of a series of rules and user defined functions. Each rule contains one pattern and action pair. Rules are separated by newline or semi-colons (;
). Typically, an awk program looks like this:
1
2
3 pattern { action }
pattern { action }
...When
awk
process data, if the pattern matches the record, it performs the specified action on that record. When the rule has no pattern, all records (lines) are matched.An awk action is enclosed in braces (
{}
) and consists of statements. Each statement specifies the operation to be performed. An action can have more than one statement separated by newline or semi-colons (;
). If the rule has no action, it defaults to printing the whole record.Awk supports different types of statements, including expressions, conditionals, input, output statements, and more. The most common awk statements are:
exit
- Stops the execution of the whole program and exits.next
- Stops processing the current record and moves to the next record in the input data.printf
- Gives you more control over the output format, similar to C and bashprintf
.When writing awk programs, everything after the hash mark
(#)
and until the end of the line is considered to be a comment. Long lines can be broken into multiple lines using the continuation character, backslash (\
)
一个awk程序应该包括一系列规则和用户定义的函数。每一条规则都应该包括一条模式和对应的动作。每一条规则应该使用换行符或者分号(;)分隔开。因此一个awk程序应该写成这样:
1 | pattern { action } |
或者
1 | pattern { action } ; pattern { action } ; ... |
pattern - pattern代表匹配字符串,若字符串匹配了一行或多行数据,那么就会对匹配的行执行对应的动作(action)
action - 动作用卷括号括起来,里面写有语句,每条语句应该用换行符或者分号(;)隔开。如果动作中没有语句,那么默认的动作是{print},即打印整行。
我们来举个例子吧:
1 | awk '/word/{print $1","$3}' awk_test.txt |
其中"/word/“代表pattern,而”{print $1",“$3}“代表action,里面有一条语句(print $1”,”$3)。这个脚本的功能就是搜索包含"word"的行数据,然后打印行数据中的第一个和第三个数据字段,并且这两个数据字段用逗号隔开。
awk语言语法可以参考以下链接:
AWK Language Programming - Table of Contents
The GNU Awk User’s Guide
Records和Data Filed
首先要明白awk程序读入输入文件时,输入文件内容会被划分为Records和Fields。简单理解就是,输入的文件内容会被按行和列进行划分。每行数据叫Record,每列数据叫Data Filed。
名称 | 描述 |
---|---|
Record | 记录(每一行数据/信息) |
Data Filed | 数据字段/数据域(数据列/列信息) |
每一行的数据可以被分割为数据字段,每个字段可以由TAB,SPACE进行分割。
让我们用一个实例看看它们到底是什么吧,比如有如下sample.txt
1 | This is sample file. |
该文本有四行,那么就有四行records,第1个record就是"This is sample file.“;第2个record就是"Java is programming language.”;第3个record就是"This is Java tutorial";第4个record就是"I know Java very well."。
第1~3行有4个Data fileds,而第4行有5个Data fileds,最后一个Data filed是"well."。
数据字段的分隔符默认是Space,因此FS变量存储的是Space。记录之间的分隔符是换行符,因此RS变量存储的是换行符。
Record Sperator和Filed Sperator
Record Sperator: 记录分隔符,又称行分隔符,简称RS.
Filed Sperator: 域分隔符,又称为字段分隔符,简称FS.
理解记录和数据字段后,RS和FS就很容易理解了:
- RS用于分割每一行数据,默认的RS是换行符(newline character)。
- FS用于分割每一行数据中数据字段,默认的FS是空格,当然还包括制表符(TAB)。
实例材料
awk_test.txt(这里我使用老男孩培训机构的视频中的实例材料)
1 | Zhang Dandan 41117397 :250:100:175 |
为了方便查看空白的内容是用了什么特殊转义字符,我使用cat -A命令进行打印
1 | cat -A awk_test.txt |
可以看到每行都是是以Tab(^I表示Tab)进行分隔数据字段的。
awk内置变量
变量名 | 描述 |
---|---|
FS | Field Separtor - 用于存储数据字段分隔符 |
NR | The number of the current record - 用于存储每一行信息的行号 |
$NR | 表示第n行的第n个数据字段 |
NF | The number of fields in the record - 用于存储每一行信息中数据字段的数量 |
$NF | 表示存储每一行最后一个数据字段 |
$0 - $n | n代表第n个数据字段(n=1,2,…,i) |
只要知道如果表达式前面加上’NR和$NF和n都是表示数据字段,$0实际上把整行当做一个数据字段。
$0 ~ $n的使用
Awk actually uses some variables for each data field found.
- $0 for whole line
- $1 for first field
- $2 for second field
- $3 for third field
- $n for nth field
打印第一个数据字段的实例
1 | awk '{print $1}' sample.txt |
可以看到$1指的是每一行的第一个数据字段。
打印多个数据字段的实例
1 | awk '{print $1","$3}' awk_test.txt # 数据字段以逗号进行分隔显示 |
FS变量的使用
FS(Field Separtor) - 用于存储数据字段分隔符的变量
指定单个分隔符
你也可以指定域分隔符,可以’-F’后接域分隔符进行指定:
1 | awk -F',' '{print $1}' countries.csv |
其中countries.csv内容如下:
1 | #Country,Population,Captital |
输出结果:
1 | #Country |
'-F’相当于内置变量FS, 指定的分割字符是设置到该变量中。
指定多个分隔符
1 | awk -F'["\t":]+' '/Zhang/{print $1,$2,$3,$4,$5,$6}' awk_test.txt |
'[“\t”:]+'表示有分隔符"\t"或":"匹配一次或多次。这种写法实际上符合正则表达式的写法。
‘+’ - 表示匹配分隔符一次或多次。
‘[]’ - 分隔符集合,里面的每一个分隔符为"或"的逻辑关系。
以下三种写法都正确
1 | awk -F'["\t":]+' '/Zhang/{print $1,$2,$3,$4,$5,$6}' awk_test.txt |
指定多个分隔符的另一种方法
1 | awk -vFS='["\t":]+' '/Zhang/{print $1,$2,$3,$4,$5,$6}' awk_test.txt |
指定多个分隔符的还有一种方法在两个特性的pattern中有提及——BEGIN BLOCK中可以直接设置FS变量。
NR变量的使用
NR(The number of the current record) - 用于存储一行信息的行号的变量
打印输入文件内容的单行、多行、指定行的实例
1 | awk 'NR==2' awk_test.txt |
$NR和NR的区别
1 | cat test.txt |
$NR表示第n行的第n个数据字段,NR表示每行的行号
NF变量的使用
NF(The number of fields in the record) - 用于存储一行信息有多少个字段的变量
$NF和NF的区别
Fields (The GNU Awk User’s Guide):
…
NF
is a predefined variable whose value is the number of fields in the current record.awk
automatically updates the value ofNF
each time it reads a record. No matter how many fields there are, the last field in a record can be represented by$NF
.
$NF和NF实例
1 | cat awk_nf.txt |
可以看出$NF表示最后一个数据字段,NF表示每一行的行号
定义变量
'-v’用于设置变量。下面给出非常规用法,但可以帮助理解该选项:
1 | awk -v name='violet' 'BEGIN {print name}' |
Output:
1 | violet |
可以看到上述例子中awk仅执行了BEGIN block,按照awk的执行流程,由于没有指定输入的文件,因此不会读入文件内容。
'-v’一般用于awk的执行流程中BEGIN block中,这一点从awk使用文档有提及:
-v var=val
–assign var=val
Assign the value val to the variable var, before execution of the program begins. Such variable values are available to the BEGIN block of an AWK program.
awk模式 | awk pattern
我们要在输入文件中查找符合要求的record,那么我们需要研究下pattern,可以参考The GNU Awk User’s Guide-Pattern-Overview。
在awk脚本设计已经介绍了pattern是干什么用的了。
应用 - “显示xiaoyu的姓氏和ID号码”
应用 - “姓氏是Zhang的人,显示他的第二次捐款金额及他的名字”
1 | awk -F'["\t":]+' '/Zhang/{print $2, $(NF-1)}' awk_test.txt |
波浪号(~)运用
Reference:~ operator | GNU Awk User’s Guide.
~(波浪号,Tilde)用于pattern匹配。
波浪号语法格式
1 | exp ~ /regexp/ |
exp - 指定匹配源(source),即在哪里进行匹配。可以$0,n,表示在这些数据字段中做匹配。
/regexp/ - 指定以何种方式进行匹配。
一个波浪号语法实例的分析
1 | $1 ~ /word/ |
该实例的功能:在每行的第一个数据字段中做匹配,如果某行的第一个数据字段中包含"word",那么就代表匹配成功,接下来就需要可以执行动作(action)了。
实际上形如
1 | awk 'pattern{action}' input_file |
这样的命令默认都会匹配当前行.即每读入输入文件的一行,awk都会对当前行进行匹配,因此上述命令相当于如下命令
1 | awk '$0 ~ pattern{action}' input_file |
应用 - “显示所有以41开头的ID号码的人的全名和ID号码”
1 | awk '$3 ~ /^41/{print}' awk_test.txt |
应用 - “显示所有ID号码最后一位数字是1或5的人的全名”
1 | awk '$3 ~ /[15]$/{print $1$2}' awk_test.txt |
其他方法
1 | awk '$3 ~ /1$|5$/{print $1$2}' awk_test.txt |
应用 - “显示Xiaoyu的捐款,每个数额都有以$开头, 如$110$220$330”
1 | awk -F'[\t:]+' '/Xiaoyu/{print "$"$(NF-2)"$"$(NF-1)"$"$NF}' awk_test.txt |
其他方法
1 | gusb(需要替换的部分, 替换信息, 具体数据字段) |
应用 - 排除空行/注释信息
1 | grep -Ev '^#|^$' INPUT_FILE |
a 对日志信息进行统计(计数)
b 对日志信息数值进行求和 客户端-下载 服务端-上传 消耗网络流量
c (数组)进行排序分析
两个特殊的pattern
在awk工作流程中看到BEGIN和END BLOCK,这两个BLOCK用于BEGIN/END pattern。
BEGIN/END pattern不是用来匹配记录的,而是用来匹配BEGIN/END BLOCK。BEGIN/END BLOCK用于在awk程序开始阶段或结束阶段(清理阶段)执行某些动作的。
GNU Awk User’s Guide-7.1.4 The BEGIN and END Special Patterns:
All the patterns described so far are for matching input records. The
BEGIN
andEND
special patterns are different. They supply startup and cleanup actions forawk
programs.BEGIN
andEND
rules must have actions; there is no default action for these rules because there is no current record when they run.BEGIN
andEND
rules are often referred to as “BEGIN
andEND
blocks” by longtimeawk
programmers.
其语法格式如下
1 | awk [OPTIONS...] '[BEGIN{STATEMENT_1;STATEMENT_2;...}] pattern{} [END{STATEMENT_1;STATEMENT_2;...}]' |
其中"BEGIN{STATEMENT_1;STATEMENT_2;…}"是可选的,因此使用方括号([])表示,"END{STATEMENT_1;STATEMENT_2;…}"也是可选的。
一个符合该语法格式的实例
1 | awk 'BEGIN{print "开始阶段"} {print} END{print "清理阶段"}' awk_test.txt |
可以看到BEGIN就是一个PATTERN,END也是一个PATTERN。它们匹配对应的BLCOK后,会执行对应的动作,这里的动作都是打印文本消息。
我们可以用BEGIN BLOCK为数据添加列标题
1 | column -t 用于创建表格 |
我们可以用BEGIN BLOCK中修改内置分隔符变量
1 | awk 'BEGIN{FS=":"}{print $2}' awk_test.txt |
统计普通用户
普通用户登录的shell都是’/bin/bash’
!的使用
1 | cat test.txt |
awk应用
awk脚本支持算术运算
1 | awk 'BEGIN{i++; print i}' |
求和应用- 统计/etc/services中空行数
1 | awk '/^$/{i++} END{print i}' /etc/services |