目录
51.Awk 命令语法
52.Awk 程序结构(BEGIN,body,END)区域
53.打印命令
54.模式匹配
Awk
是一个维护和处理文本数据文件的强大语言。在文本数据有一定的格式,即每行数据包
含多个以分界符分隔的字段时,显得尤其有用。即便是输入文件没有一定的格式,你仍然可
以使用
awk
进行基本的处理。
Awk
当然也可以没有输入文件,那不是必须的。简言之,
AWK
是一种能处理从琐碎的小事到日常例行公事的强大语言。
学习
AWK
的难度要比学习其他任意语言的难度都小。如果你已经掌握了
C
语言,那么你会
发现学习
AWK
将会是如此简单和容易。
AWK
最开始由三个人开发——
A.Aho
、
B.W.Kernighan
和
P.Weinberger
。所有
AWK
的名字来
自他们名字的第一个字母。
下面是
AWK
的几个变种:
AWK
是最原始的
AWK
。
NAWK
是
new AWK
GAWK
是
GNU AWK
。所有
linux
发行版都默认使用
GAWK
,它和
AWK
以及
NAWK
完全兼容。
本书包含了原始
AWK
的所有基础功能,以及
GAWK
特有的一些高级功能。在安装了
NAWK
或
GAWK
的操作系统上,你仍然可以直接使用
awk
命令,它会根据情况调用
nawk
或
gawk
。
以
linux
系统为例,你会看到
awk
是一个指向
gawk
的符号链接,所以在
linux
上执行
awk
或
gawk
将会调用
gawk
:
$ ls -l /bin/awk /bin/gawk
lrwxrwxrwx 1 root root 4 Apr 8 2011 /bin/awk -> gawk
-rwxr-xr-x 1 root root 319336 Dec 3 2008 /bin/gawk
本书示例将用到下面三个文件,请先建立它们,然后用它们来运行所有示例。
employee.txt
文件
employee.txt
文件以逗号作为字段分界符,包含
5
个雇员的记录,其格式如下:
employee-number,employee-name,employee-title
建立该文件
:
$ vi employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
items.txt
文件
items.txt
是一个以逗号作为字段分界符的文本文件,包含
5
条记录,其格式如下:
items-number,item-description,item-category,cost,quantity-available
建立该文件
:
$ vi items.txt
101,HD Camcorder,Video,210,10
102,Refrigerator,Appliance,850,2
103,MP3 Player,Audio,270,15
104,Tennis Racket,Sports,190,20
105,Laser Printer,Office,475,5
items-sold.txt
文件
items-sold.txt
是一个以空格作为字段分界符的文本文件,包含
5
条记录。每条记录都是特定
商品的编号以及当月的销售量
(6
个月
)
。因此每条记录有
7
个字段。第一个字段是商品编号,
第二个字段到第七个字段是
6
个月内每月的销售量。其格式如下:
item-number qty-sold-month1 qty-sold-month2 qty-sold-month3 qty-sold-month4
qty-sold-month5 qty-sold-month6
建立该文件
:
$ cat items-sold.txt
101 2 10 5 8 10 12
102 0 1 4 3 0 2
103 10 6 11 20 5 13
104 2 3 4 0 6 5
105 10 2 5 7 12 6
51.Awk 命令语法
Awk
基础语法
:
Awk –Fs ‘/pattern/ {action}’ input-file
(或者)
Awk –Fs ‘{action}’ input-file
上面语法中:
z
-F
为字段分界符。如果不指定,默认会使用空格作为分界符。
z
/pattern/
和
{action}
需要用单引号引起来。
z
/pattern/
是可选的。如果不指定,
awk
将处理输入文件中的所有记录。如果指定一
个模式,
awk
则只处理匹配指定的模式的记录。
z
{action}
为
awk
命令,可以是单个命令,也可以多个命令。整个
action(
包括里面的
所有命令
)
都必须放在
{
和
}
之间。
z
Input-file
即为要处理的文件
下面是一个演示
awk
语法的非常简单的例子
:
$ awk -F: '/mail/ {print $1}' /etc/passwd
mail
mailnull
这个例子中
:
z
-F
指定字段分界符为冒号,即各个字段以冒号分隔。请注意,你也可以把分界符
用双引号引住,
-F”:”
也是正确的。
z
/mail/
指定模式,
awk
只会处理包含关键字
mail
的记录
z
{print $1}
动作部分,该动作只包含一个
awk
命令,它打印匹配
mail
的每条记录的
第
1
个字段
z
/etc/passwd
即是输入文件
把 awk 命令放入单独的文件中(awk 脚本)当需要执行很多 awk 命令时,可以把/pattern/{action}这一部分放到单独的文件中,然后调 用它:
awk –Fs –f myscript.awk input-file
myscript.awk 可以使用任意扩展名(或者不用扩展名)。但是加上扩展名.awk 便于维护,也可
以在这个文件中设置字段分界符(后面详述),然后调用:
awk –f myscript.awk input-file
52.Awk 程序结构(BEGIN,body,END)区域
典型的
awk
程序包含下面三个区域
:
1. BEGIN
区域
Begin
区域的语法
:
BEGIN { awk-commands }
BEGIN
区域的命令只最开始、在
awk
执行
body
区域命令之前执行一次。
z
BEGIN
区域很适合用来打印报文头部信息,以及用来初始化变量。
z
BEGIN
区域可以有一个或多个
awk
命令
z
关键字
BEGIN
必须要用大写
z
BEGIN
区域是可选的
2. body
区域
body
区域的语法
:
/pattern/ {action}
body
区域的命令每次从输入文件读取一行就会执行一次
z
如果输入文件有
10
行,那
body
区域的命令就会执行
10
次
(
每行执行一次
)
z
Body
区域没有用任何关键字表示,只有用正则模式和命令。
3. END block
END
区域的语法
:
END { awk-commands }
END
区域在
awk
执行完所有操作后执行,并且只执行一次。
z
END
区域很适合打印报文结尾信息,以及做一些清理动作
z
END
区域可以有一个或多个
awk
命令
z
关键字
END
必须要用大写
z
END
区域是可选的
Awk
的执行流程
下面的例子包含上上述的三个区域:
$ awk 'BEGIN { FS=":";print "----header----" } \
/mail/ {print $1} \
END {print "----footer----"}' /etc/passwd
----header----
mail
mailnull
----footer----
提示:如果命令很长,即可以放到单行执行,也可以用
\
折成多行执行。上面的例子用
\
把命
令折成了
3
行。
在这个例子中:
z
BEGIN { FS=”:”;print “----header----“ }
为
BEGIN
区域,它设置了字段分界符变量
FS(
下
文详述
)
的值,然后打印报文头部信息。这个区域仅在
body
区域循环之前执行一次。
z
/mail/{print $1}
是
body
区域,包含一个正则模式和一个动作,即在输入文件中搜索
包含关键字
mail
的行,并打印第一个字段。
z
END {print “----footer----“ }
是
END
区域,打印报文尾部信息。
z
/etc/passwd
是输入文件,每行记录都会执行一次
body
区域里的动作。
上面的例子中,除了可以在命令行上执行外,还可以通过脚本执行。
首先建立下面的文件
myscript.awk,
它包含了
begin,body
和
end
:
$vi myscript.awk
BEGIN {
FS=":"
print "---header---"
}
/mail/ {
print $1
}
END {
print "---footer---"
}
然后,如下所示,在
/etc/passwd
上执行
myscript.awk
文件:
$awk -f myscript.awk /etc/passwd
---header---
mail
---footer---
请注意,
awk
脚本中,注释以
#
开头。如果要编写复杂的
awk
脚本,最后接受下面的建议:
在
*awk
文件中写上足够多的注释,这样以后再次使用该脚本时,更易于读懂。
下面是随机列出的一些简单的例子,用例演示
awk
各个区域的不同组合方式:
只有
body
区域
:
awk –F: ‘{ print $1 }’ /etc/passwd
同时具有
begin,body
和
end
区域
:
awk –F: ‘BEGIN{printf “username\n-------\n”}\
{ print $1 }\
END {print “----------“ }’ /etc/passwd
只有
begin
和
body
区域
:
Awk –F: ‘BEGIN {print “UID”} {print $3}’ /etc/passwd
关于使用
BEGIN
区域的提示
:
只使用
BEGIN
区域在
awk
中是符合语法的。在没有使用
body
区域时,不需要指定输入文件,
因为
body
区域只在输入文件上执行。所以在执行和输入文件无关的工作时,可以只使用
BEGIN
区域。下面的不少例子中,只包含
BEGIN
区域,用来说明
awk
的不同部分是如何执行
的。你可以因地制宜地使用下面的例子。
只包含
BEGIN
的简单示例
:
$awk ‘BEGIN { print “Hello,World!” }’
Hello World!
多个输入文件
:
注意,可以为
awk
指定多个输入文件。如果指定了两个文件,那么
body
区域会首先在第一
个文件的所有行上执行,然后在第二个文件的所有行上执行。
多个输入文件示例
:
$awk 'BEING { FS=":";print "---header---" }\
/mail/ {print $1}\
END { print "---footer---"}' /etc/passwd /etc/group
mail:x:8:12:Mailer
mail:x:12:
maildrop:!:59:
---footer---
注意,即是指定了多个文件,
BEGIN
和
END
区域,仍然只会执行一次。
53.打印命令
默认情况下,
awk
的打印命令
print(
不带任何参数
)
会打印整行数据。下面的例子等价于
”cat
employee.txt”
命令
.
$awk '{print}' employee.txt
101,John Doe,CEO
102,Jason Smith,IT Manager
103,Raj Reddy,Sysadmin
104,Anand Ram,Developer
105,Jane Miller,Sales Manager
也可以通过传递变量
”$
字段序号
”
作为
print
的参数来指定要打印的字段。我们猜想例子应该
只打印雇员名称
(
第
2
个字段
)
$awk '{print $2}' employee.txt
Doe,CEO
Smith,IT
Reddy,Sysadmin
Ram,Developer
Miller,Sales
等等,这个输出好像和预期不符。它打印了从姓氏开始直到记录结尾的所有内容。这是因为
awk
默认的字段分隔符是空格,
awk
准确地执行了我们要求的动作,它以空格作为分隔符,
打印第
2
个字段。当使用默认的空格作为字段分隔符时,
101,Johne
变成了第一条记录的第
一个字段,
Doe,CEO
变成了第二个字段。因此上面例子中,
awk
把
Doe,CEO
作为第二个字段
打印出来了。
要解决这个文件,应该使用-F 选项为 awk 指定一个逗号”,”最为字段分隔符。
$awk -F ',' '{print $2}' employee.txt
John Doe
Jason Smith
Raj Reddy
Anand Ram
Jane Miller
当字段分隔符是单个字符时,下面的所有写法都是争取的,即可以把它放在单引号或双引号
中,或者不使用引号:
awk –F ‘,’ ‘{print $2}’ employee.txt
awk –F “,” ‘{print $2}’ employee.txt
awk –F , ‘{print $2}’ employee.txt
ᨀ示
:
也可使用
FS
变量来达到同样的目的。后面会介绍这个
awk
内置变量的用法。
一个简单的例子,用来输出雇员姓名,职位,同时附带
header
和
footer
信息
:
$awk 'BEGIN{FS=",";print "---------\nName Title\n------------\n";}\
{print $2,"\t",$3}\
END {print "-------------------"}' employee.txt
---------
Name Title
------------
John Doe CEO
Jason Smith IT Manager
Raj Reddy Sysadmin
Anand Ram Developer
Jane Miller Sale
这个例子中,输出结果各字段并没有很好地对齐,后面章节将会介绍如何处理这个问题。这
个例子还展示了如何使用
BEGIN
来打印
header
以及如何使用
END
来打印
footer.
请注意,
$0
代表整条记录。下面两个命令是等价的,都打印
employee.txt
的所有行
:
awk ‘{print}’ employee.txt
awk ‘{print $0}’ employee.txt
54.模式匹配
你可以只在匹配特殊模式的行数执行
awk
命令。
下面的例子只打印管理者的姓名和职位:
$awk -F ',' '/Manager/ {print $2,$3}' employee.txt
Jason Smith IT Manager
Jane Miller Sales Manager
下面的例子只打印雇员
id
为
102
的雇员的信息:
$awk -F ',' '/^102/{print "Emp id 102 is",$2}' \
> employee.txt
Emp id 102 is Jason Smith
资料来源于《SedandAwk101Hacks》,大家有兴趣可以买一本,也可以关注我,我更新完它。
曾经,我花费大半月将它们跑完,现在啥都忘了,还是要常用。
只为学习交流,不为获利,侵权联系立删。