windows ubuntu sed,awk,grep篇,8,Awk 语法和基础命令

发布于:2024-05-04 ⋅ 阅读:(23) ⋅ 点赞:(0)
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》,大家有兴趣可以买一本,也可以关注我,我更新完它。

曾经,我花费大半月将它们跑完,现在啥都忘了,还是要常用。

只为学习交流,不为获利,侵权联系立删。


网站公告

今日签到

点亮在社区的每一天
去签到