转自http://blog.csdn.net/yayong/article/details/178145
http://www.ibm.com/developerworks/cn/linux/l-cn-awk-httplog/index.html
Awk 是一种非常好的语言,同时有一个非常奇怪的名称。在本系列(共三篇文章)的第一篇文章中,Daniel Robbins 将使您迅速掌握 awk 编程技巧。随着本系列的进展,将讨论更高级的主题,最后将演示一个真正的高级 awk 演示程序。
捍卫 awk
在本系列文章中,我将使您成为精通 awk 的编码人员。我承认,awk 并没有一个非常好听且又非常“时髦”的名字。awk 的 GNU 版本(叫作 gawk)听起来非常怪异。那些不熟悉这种语言的人可能听说过 "awk", 并可能认为它是一组落伍且过时的混乱代码。它甚至会使最博学的 UNIX 权威陷于错乱的边缘(使他不断地发出 "kill -9!" 命令,就象使用咖啡机一样)。
的确,awk 没有一个动听的名字。但它是一种很棒的语言。awk 适合于文本处理和报表生成,它还有许多精心设计的特性,允许进行需要特殊技巧程序设计。与某些语言不同,awk 的语法较为常见。它借鉴了某些语言的一些精华部分,如 C 语言、python 和 bash(虽然在技术上,awk 比 python 和 bash 早创建)。awk 是那种一旦学会了就会成为您战略编码库的主要部分的语言。
第一个 awk
让我们继续,开始使用 awk,以了解其工作原理。在命令行中输入以下命令:
$ awk '{ print }' /etc/passwd
|
您将会见到 /etc/passwd 文件的内容出现在眼前。现在,解释 awk 做了些什么。调用 awk 时,我们指定 /etc/passwd 作为输入文件。执行 awk 时,它依次对 /etc/passwd 中的每一行执行 print 命令。所有输出都发送到 stdout,所得到的结果与与执行catting /etc/passwd完全相同。
现在,解释 { print }
代码块。在 awk 中,花括号用于将几块代码组合到一起,这一点类似于 C 语言。在代码块中只有一条 print 命令。在 awk 中,如果只出现 print 命令,那么将打印当前行的全部内容。
这里是另一个 awk 示例,它的作用与上例完全相同:
$ awk '{ print $0 }' /etc/passwd
|
在 awk 中,$0
变量表示整个当前行,所以 print
和 print $0
的作用完全一样。
如果您愿意,可以创建一个 awk 程序,让它输出与输入数据完全无关的数据。以下是一个示例:
$ awk '{ print "" }' /etc/passwd
|
只要将 "" 字符串传递给 print 命令,它就会打印空白行。如果测试该脚本,将会发现对于 /etc/passwd 文件中的每一行,awk 都输出一个空白行。再次说明, awk 对输入文件中的每一行都执行这个脚本。以下是另一个示例:
$ awk '{ print "hiya" }' /etc/passwd
|
运行这个脚本将在您的屏幕上写满 hiya。:)
多个字段
awk 非常善于处理分成多个逻辑字段的文本,而且让您可以毫不费力地引用 awk 脚本中每个独立的字段。以下脚本将打印出您的系统上所有用户帐户的列表:
$ awk -F":" '{ print $1 }' /etc/passwd
|
上例中,在调用 awk 时,使用 -F 选项来指定 ":" 作为字段分隔符。awk 处理 print $1
命令时,它会打印出在输入文件中每一行中出现的第一个字段。以下是另一个示例:
$ awk -F":" '{ print $1 $3 }' /etc/passwd
|
以下是该脚本输出的摘录:
halt7
operator11
root0
shutdown6
sync5
bin1
....etc.
|
如您所见,awk 打印出 /etc/passwd 文件的第一和第三个字段,它们正好分别是用户名和用户标识字段。现在,当脚本运行时,它并不理想 -- 在两个输出字段之间没有空格!如果习惯于使用 bash 或 python 进行编程,那么您会指望 print $1 $3
命令在两个字段之间插入空格。然而,当两个字符串在 awk 程序中彼此相邻时,awk 会连接它们但不在它们之间添加空格。以下命令会在这两个字段中插入空格:
$ awk -F":" '{ print $1 " " $3 }' /etc/passwd
|
以这种方式调用 print 时,它将连接 $1
、" " 和 $3
,创建 可读的输出。当然,如果需要的话,我们还可以插入一些文本标签:
$ awk -F":" '{ print "username: " $1 "ttuid:" $3" }' /etc/passwd
|
这将产生以下输出:
username: halt uid:7
username: operator uid:11
username: root uid:0
username: shutdown uid:6
username: sync uid:5
username: bin uid:1
....etc.
|
外部脚本
将脚本作为命令行自变量传递给 awk 对于小的单行程序来说是非常简单的,而对于多行程序,它就比较复杂。您肯定想要在外部文件中撰写脚本。然后可以向 awk 传递 -f 选项,以向它提供此脚本文件:
$ awk -f myscript.awk myfile.in
|
将脚本放入文本文件还可以让您使用附加 awk 功能。例如,这个多行脚本与前面的单行脚本的作用相同,它们都打印出 /etc/passwd 中每一行的第一个字段:
BEGIN {
FS=":"
}
{ print $1 }
|
这两个方法的差别在于如何设置字段分隔符。在这个脚本中,字段分隔符在代码自身中指定(通过设置 FS 变量),而在前一个示例中,通过在命令行上向 awk 传递 -F":" 选项来设置 FS。通常,最好在脚本自身中设置字段分隔符,只是因为这表示您可以少输入一个命令行自变量。我们将在本文的后面详细讨论 FS 变量。
BEGIN 和 END 块
通常,对于每个输入行,awk 都会执行每个脚本代码块一次。然而,在许多编程情况中,可能需要在 awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况,awk 允许您定义一个 BEGIN 块。我们在前一个示例中使用了 BEGIN 块。因为 awk 在开始处理输入文件之前会执行 BEGIN 块,因此它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它在程序中以后会引用的全局变量的极佳位置。
awk 还提供了另一个特殊块,叫作 END 块。awk 在处理了输入文件中的所有行之后执行这个块。通常,END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。
规则表达式和块
awk 允许使用规则表达式,根据规则表达式是否匹配当前行来选择执行独立代码块。以下示例脚本只输出包含字符序列 foo
的那些行:
/foo/ { print }
|
当然,可以使用更复杂的规则表达式。以下脚本将只打印包含浮点数的行:
/[0-9]+.[0-9]*/ { print }
|
表达式和块
还有许多其它方法可以选择执行代码块。我们可以将任意一种布尔表达式放在一个代码块之前,以控制何时执行某特定块。仅当对前面的布尔表达式求值为真时, awk 才执行代码块。以下示例脚本输出将输出其第一个字段等于 fred
的所有行中的第三个字段。如果当前行的第一个字段不等于 fred
,awk 将继续处理文件而不对当前行执行 print
语句:
$1 == "fred" { print $3 }
|
awk 提供了完整的比较运算符集合,包括 "=="、"<"、">"、"<="、">=" 和 "!="。另外,awk 还提供了 "~" 和 "!~" 运算符,它们分别表示“匹配”和“不匹配”。它们的用法是在运算符左边指定变量,在右边指定规则表达式。如果某一行的第五个字段包含字符序列 root
, 那么以下示例将只打印这一行中的第三个字段:
$5 ~ /root/ { print $3 }
|
条件语句
awk 还提供了非常好的类似于 C 语言的 if
语句。如果您愿意,可以使用 if
语句重写前一个脚本:
{
if ( $5 ~ /root/ ) {
print $3
}
}
|
这两个脚本的功能完全一样。第一个示例中,布尔表达式放在代码块外面。而在第二个示例中,将对每一个输入行执行代码块,而且我们使用 if
语句来选择执行 print 命令。这两个方法都可以使用,可以选择最适合脚本其它部分的一种方法。
以下是更复杂的 awk if
语句示例。可以看到,尽管使用了复杂、嵌套的条件语句,if
语句看上去仍与相应的 C 语言 if
语句一样:
{
if ( $1 == "foo" ) {
if ( $2 == "foo" ) {
print "uno"
} else {
print "one"
}
} else if ($1 == "bar" ) {
print "two"
} else {
print "three"
}
}
|
使用 if
语句还可以将代码:
! /matchme/ { print $1 $3 $4 }
|
转换成:
{
if ( $0 !~ /matchme/ ) {
print $1 $3 $4
}
}
|
这两个脚本都只输出不包含 matchme
字符序列的那些行。此外,还可以选择最适合您的代码的方法。它们的功能完全相同。
awk 还允许使用布尔运算符 "||"(逻辑与)和 "&&"(逻辑或),以便创建更复杂的布尔表达式:
( $1 == "foo" ) && ( $2 == "bar" ) { print }
|
这个示例只打印第一个字段等于 foo
且第二个字段等于 bar
的那些行。
数值变量!
至今,我们不是打印字符串、整行就是特定字段。然而,awk 还允许我们执行整数和浮点运算。通过使用数学表达式,可以很方便地编写计算文件中空白行数量的脚本。以下就是这样一个脚本:
BEGIN { x=0 }
/^$/ { x=x+1 }
END { print "I found " x " blank lines. :)" }
|
在 BEGIN 块中,将整数变量 x
初始化成零。然后,awk 每次遇到空白行时,awk 将执行 x=x+1
语句,递增 x
。处理完所有行之后,执行 END 块,awk 将打印出最终摘要,指出它找到的空白行数量。
字符串化变量
awk 的优点之一就是“简单和字符串化”。我认为 awk 变量“字符串化”是因为所有 awk 变量在内部都是按字符串形式存储的。同时,awk 变量是“简单的”,因为可以对它执行数学操作,且只要变量包含有效数字字符串,awk 会自动处理字符串到数字的转换步骤。要理解我的观点,请研究以下这个示例:
x="1.01"
# We just set x to contain the *string* "1.01"
x=x+1
# We just added one to a *string*
print x
# Incidentally, these are comments :)
|
awk 将输出:
2.01
|
有趣吧!虽然将字符串值 1.01
赋值给变量 x
,我们仍然可以对它加 一。但在 bash 和 python 中却不能这样做。首先,bash 不支持浮点运算。而且,如果 bash 有“字符串化”变量,它们并不“简单”;要执行任何数学操作,bash 要求我们将数字放到丑陋的 $( )
) 结构中。如果使用 python,则必须在对 1.01
字符串执行任何数学运算之前,将它转换成浮点值。虽然这并不困难,但它仍是附加的步骤。如果使用 awk,它是全自动的,而那会使我们的代码又好又整洁。如果想要对每个输入行的第一个字段乘方并加一,可以使用以下脚本:
{ print ($1^2)+1 }
|
如果做一个小实验,就可以发现如果某个特定变量不包含有效数字,awk 在对数学表达式求值时会将该变量当作数字零处理。
众多运算符
awk 的另一个优点是它有完整的数学运算符集合。除了标准的加、减、乘、除,awk 还允许使用前面演示过的指数运算符 "^"、模(余数)运算符 "%" 和其它许多从 C 语言中借入的易于使用的赋值操作符。
这些运算符包括前后加减(i++
、--foo
)、加/减/乘/除赋值运算符( a+=3
、b*=2
、c/=2.2
、d-=6.2
)。不 仅如此 -- 我们还有易于使用的模/指数赋值运算符(a^=2
、b%=4
)。
字段分隔符
awk 有它自己的特殊变量集合。其中一些允许调整 awk 的运行方式,而其它变量可以被读取以收集关于输入的有用信息。我们已经接触过这些特殊变量中的一个,FS。前面已经提到过,这个变量让您可以设置 awk 要查找的字段之间的字符序列。我们使用 /etc/passwd 作为输入时,将 FS 设置成 ":"。当这样做有问题时,我们还可以更灵活地使用 FS。
FS 值并没有被限制为单一字符;可以通过指定任意长度的字符模式,将它设置成规则表达式。如果正在处理由一个或多个 tab 分隔的字段,您可能希望按以下方式设置 FS:
FS="t+"
|
以上示例中,我们使用特殊 "+" 规则表达式字符,它表示“一个或多个前一字符”。
如果字段由空格分隔(一个或多个空格或 tab),您可能想要将 FS 设置成以下规则表达式:
FS="[[:space:]+]"
|
这个赋值表达式也有问题,它并非必要。为什么?因为缺省情况下,FS 设置成单一空格字符,awk 将这解释成表示“一个或多个空格或 tab”。在这个特殊示例中,缺省 FS 设置恰恰是您最想要的!
复杂的规则表达式也不成问题。即使您的记录由单词 "foo" 分隔,后面跟着三个数字,以下规则表达式仍允许对数据进行正确的分析:
FS="foo[0-9][0-9][0-9]"
|
字段数量
接着我们要讨论的两个变量通常并不是需要赋值的,而是用来读取以获取关于输入的有用信息。第一个是 NF 变量,也叫做“字段数量”变量。awk 会自动将该变量设置成当前记录中的字段数量。可以使用 NF 变量来只显示某些输入行:
NF == 3 { print "this particular record has three fields: " $0 }
|
当然,也可以在条件语句中使用 NF 变量,如下:
{
if ( NF > 2 ) {
print $1 " " $2 ":" $3
}
}
|
记录号
记录号 (NR) 是另一个方便的变量。它始终包含当前记录的编号(awk 将第一个记录算作记录号 1)。迄今为止,我们已经处理了每一行包含一个记录的输入文件。对于这些情况,NR 还会告诉您当前行号。然而,当我们在本系列以后部分中开始处理多行记录时,就不会再有这种情况,所以要注意!可以象使用 NF 变量一样使用 NR 来只打印某些输入行:
(NR < 10 ) || (NR > 100) { print "We are on record number 1-9 or 101+" }
|
另一个示例:
{
#skip header
if ( NR > 10 ) {
print "ok, now for the real information!"
}
}
|
awk 提供了适合各种用途的附加变量。我们将在以后的文章中讨论这些变量。awk
相关推荐
sed 和 awk 使用实例 Sed 和 Awk 是两种强大的命令行工具,在 Unix 和 Linux 系统中广泛应用于文本处理和数据处理。本文将通过一些实例来展示 Sed 和 Awk 的使用场景和方法。 一、sed 使用实例 1. 删除 login....
"awk编程实例"意味着这个压缩包特别关注AWK的实际应用,提供了一系列的编程示例,帮助用户理解和掌握AWK的使用技巧。这些实例可能涵盖简单的数据提取到复杂的逻辑处理,有助于提升用户在数据处理方面的技能。 总的...
awk 命令用法详解 awk 是一个功能强大且灵活的文本处理工具,它可以对文本进行各种操作,如搜索、匹配、计算、格式化等。awk 的基本语法为 `awk 'pattern {action}' file`,其中 `pattern` 是模式,`action` 是对...
以下是一些使用Awk的基本概念和实例: 1. **字段分隔符(Field Separators)**:默认情况下,Awk将空格或制表符作为字段分隔符。你可以使用`-F`选项自定义分隔符,例如`awk -F ":"`将用冒号分隔字段。 2. **模式...
### AWK实例教程知识点解析 #### 一、AWK简介及背景 - **AWK**是一种功能强大的文本处理工具,最初由贝尔实验室的Alfred Aho、Peter Weinberger和Brian Kernighan共同开发,因此得名AWK。尽管这个名字听起来有些...
默认情况下,`awk`使用空格或制表符作为字段分隔符(Field Separator, FS)。但可以通过`-F`选项或内部变量`FS`自定义分隔符,如`awk -F: '{print $1}'`以冒号为分隔符打印第一列。 **3. 内置变量** `awk`提供了...
### Awk命令使用详解 #### 一、Awk简介 Awk是一种强大的文本处理语言,专为高级文本处理和数据分析而设计。它被广泛应用于快速编写脚本来处理文本文件,如日志文件、配置文件等。Awk的核心功能在于能够方便地对文本...
默认情况下,`awk`使用空格或制表符作为字段分隔符(Field Separator, FS)。可以通过内置变量`FS`来改变这个行为,例如: ```bash awk -F ',' '{ print $1 }' file.csv ``` 这会将逗号作为字段分隔符,打印CSV文件...
【awk真实实例】这篇文章主要介绍了awk这种强大的文本处理语言,并通过一系列实例帮助新手入门。awk是一种专门用于文本处理和报表生成的语言,虽然它的名字有些奇特,但其功能强大且易于学习。 awk的语法简洁明了,...
### grep、sed、awk命令实例大练习 在Linux或Unix环境中,`grep`、`sed`和`awk`是三个非常强大的文本处理工具。通过掌握这些工具的基本用法及高级功能,用户可以高效地处理各种文本文件。下面将详细介绍如何使用...
**AWK详解与使用手册** AWK是一种强大的文本分析工具,尤其在处理结构化数据时,它的灵活性和高效性使其成为Unix/Linux环境中的得力助手。这个文档将深入讲解AWK的基本概念、语法以及实际应用。 ### 1. **AWK基础...
下面是一份 awk 教程,从基础知识到高级应用,涵盖了 awk 的基本概念、语法、函数和应用实例。 awk 基础知识 awk 的基本结构是 pattern{action},其中 pattern 是awk的模式, action 是awk的动作。awk 的模式可以...
《AWK使用手册》是专为帮助读者快速掌握AWK编程语言而编写的,通过一系列具有代表性的实例和解析,让读者逐步理解并熟练运用AWK处理数据和生成报表。AWK是一种强大的文本分析工具,它能对输入数据(如文件、标准输入...
### awk实例入门教程知识点解析 #### 一、awk语言简介 awk是一种专为文本处理设计的强大脚本语言,尤其适用于数据格式化、过滤和报告生成。它的命名来源于三位创造者:Alfred Aho、Peter Weinberger 和 Brian ...
本指南将深入解析这些工具的使用实例和精解,帮助读者理解并掌握这些强大的命令行工具。 **Bash Shell** 是Linux系统中的默认shell,它是一种交互式、解释型的命令行接口。Bash提供了一系列的命令、变量、运算符...
最牛逼的Linux awk命令详细介绍和实例快速学习