本文出自http://hi.baidu.com/cjy2020/blog/item/b18c0587a0476026c65cc3c7.html,感觉很好,所以转载收藏

AWK 实用工具带有其自己的 自包含语言,它不仅是 Linux 中也是任何环境中现有 的功能最强大的数据处 理引擎之一。这种编程 及数据操作语言(其名 称得自于它的创始人 Alfred Aho、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最 大功能取决于一个人所 拥有的知识。它允许您 创建简短的程序,这些 程序读取输入文件、为 数据排序、处理数据、 对输入执行计算以及生 成报表,还有无数其他 的功能。

AWK 是什么?

最简单地说,AWK 是一种用于处理文本的 编程语言工具。AWK 实用工具的语言在很多 方面类似于 shell 编程语言,尽管 AWK 具有完全属于其本身的 语法。在最初创造 AWK 时,其目的是用于文本 处理,并且这种语言的 基础是,只要在输入数 据中有模式匹配,就执 行一系列指令。该实用 工具扫描文件中的每一 行,查找与命令行中所 给定内容相匹配的模式 。如果发现匹配内容, 则进行下一个编程步骤 。如果找不到匹配内容 ,则继续处理下一行。

尽管操作可能会很复杂 ,但命令的语法始终是 :

awk '{pattern + action}' {filenames }

其中 pattern 表示 AWK 在数据中查找的内容, 而 action 是在找到匹配内容时所 执行的一系列命令。花 括号 ({}) 不需要在程序中始终出 现,但它们用于根据特 定的模式对一系列指令 进行分组。

了解字段

实用工具将每个输入行 分为记录和字段。记录 是单行的输入,而每条 记录包含若干字段。默 认的字段分隔符是空格 或制表符,而记录的分 隔符是换行。虽然在默 认情况下将制表符和空 格都看作字段分隔符( 多个空格仍然作为一个 分隔符),但是可以将 分隔符从空格改为任何 其它字符。

为了进行演示,请查看 以下保存为 emp_names 的员工列表文件:

46012 DULANEY EVAN MOBILE AL
46013 DURHAM JEFF MOBILE AL
46015 STEEN BILL MOBILE AL
46017 FELDMAN EVAN MOBILE AL
46018 SWIM STEVE UNKNOWN AL
46019 BOGUE ROBERT PHOENIX AZ
46021 JUNE MICAH PHOENIX AZ
46022 KANE SHERYL UNKNOWN AR
46024 WOOD WILLIAM MUNCIE IN
46026 FERGUS SARAH MUNCIE IN
46027 BUCK SARAH MUNCIE IN
46029 TUTTLE BOB MUNCIE IN

当 AWK 读取输入内容时,整条 记录被分配给变量 $0。每个字段以字段 分隔符分开,被分配给 变量 $1、$2、$3 等等。一行在本质上可 以包含无数个字段,通 过字段号来访问每个字 段。因此,命令

awk '{print $1,$2,$3,$ 4,$5}' names

将会产生的打印输出是

46012 DULANEY EVAN MOBILE AL
46013 DURHAM JEFF MOBILE AL
46015 STEEN BILL MOBILE AL
46017 FELDMAN EVAN MOBILE AL
46018 SWIM STEVE UNKNOWN AL
46019 BOGUE ROBERT PHOENIX AZ
46021 JUNE MICAH PHOENIX AZ
46022 KANE SHERYL UNKNOWN AR
46024 WOOD WILLIAM MUNCIE IN
46026 FERGUS SARAH MUNCIE IN
46027 BUCK SARAH MUNCIE IN
46029 TUTTLE BOB MUNCIE IN

值得注意的一项重要内 容是,AWK 解释由空格分隔的五个 字段,但当它打印显示 内容时,在每个字段间 只有一个空格。利用为 每个字段指定了唯一号 码的功能,您可以选择 只打印特定的字段。例 如,只打印每条记录的 姓名时,只需选择第二 个和第三个字段进行打 印:

$ awk '{print $2,$3}' emp_names
DULANEY EVAN
DURHAM JEFF
STEEN BILL
FELDMAN EVAN
SWIM STEVE
BOGUE ROBERT
JUNE MICAH
KANE SHERYL
WOOD WILLIAM
FERGUS SARAH
BUCK SARAH
TUTTLE BOB
$

您还可以指定按任何顺 序打印字段,而无论它 们在记录中是如何存在 的。因此,只需要显示 姓名字段,并且使其顺 序颠倒,先显示名字再 显示姓氏:

$ awk '{print $3,$2}' emp_names
EVAN DULANEY
JEFF DURHAM
BILL STEEN
EVAN FELDMAN
STEVE SWIM
ROBERT BOGUE
MICAH JUNE
SHERYL KANE
WILLIAM WOOD
SARAH FERGUS
SARAH BUCK
BOB TUTTLE
$

使用模式

通过包含一个必须匹配 的模式,您可以选择只 对特定的记录而不是所 有的记录进行操作。模 式匹配的最简单形式是 搜索,其中要匹配的项 目被包含在斜线 (/pattern/ ) 中。例如,只对那些居 住在阿拉巴马州的员工 执行前面的操作:

$ awk '/AL/ {print $3,$2}' emp_names
EVAN DULANEY
JEFF DURHAM
BILL STEEN
EVAN FELDMAN
STEVE SWIM
$

如果您不指定要打印的 字段,则会打印整个匹 配的条目:

$ awk '/AL/' emp_names
46012 DULANEY EVAN MOBILE AL
46013 DURHAM JEFF MOBILE AL
46015 STEEN BILL MOBILE AL
46017 FELDMAN EVAN MOBILE AL
46018 SWIM STEVE UNKNOWN AL
$

对同一数据集的多个命 令可以用分号 (;) 分隔开。例如,在一行 中打印姓名,而在另一 行中打印城市和州名:

$ awk '/AL/ {print $3,$2 ; print $4,$5}' emp_names
EVAN DULANEY
MOBILE AL
JEFF DURHAM
MOBILE AL
BILL STEEN
MOBILE AL
EVAN FELDMAN
MOBILE AL
STEVE SWIM
UNKNOWN AL
$

如果没有使用分号 (print $3,$2,$4,$ 5),则会在同一行中 显示所有内容。另一方 面,如果分别给出两个 打印语句,则会产生完 全不同的结果:

$ awk '/AL/ {print $3,$2} {print $4,$5}' emp_names
EVAN DULANEY
MOBILE AL
JEFF DURHAM
MOBILE AL
BILL STEEN
MOBILE AL
EVAN FELDMAN
MOBILE AL
STEVE SWIM
UNKNOWN AL
PHOENIX AZ
PHOENIX AZ
UNKNOWN AR
MUNCIE IN
MUNCIE IN
MUNCIE IN
MUNCIE IN
$

只有在列表中找到 AL 时才会给出字段三和字 段二。但是,字段四和 字段五是无条件的,始 终打印它们。只有第一 组花括号中的命令对前 面紧邻的命令 (/AL/) 起作用。

结果非常不便于阅读, 可以使其稍微更清晰一 些。首先,在城市与州 之间插入一个空格和逗 号。然后,在每两行显 示之后放置一个空行:

$ awk '/AL/ {print $3,$2 ; print $4", "$5" "}' emp_names
EVAN DULANEY
MOBILE, AL

JEFF DURHAM
MOBILE, AL

BILL STEEN
MOBILE, AL

EVAN FELDMAN
MOBILE, AL

STEVE SWIM
UNKNOWN, AL
$

在第四和第五个字段之 间,添加一个逗号和一 个空格(在引号之间) ,在第五个字段后面, 打印一个换行符 ( )。在 AWK 打印语句中还可以使用 那些可在 echo 命令中使用的所有特殊 字符,包括:

* (换行)
* (制表)
* (退格)
* f(进纸)
* (回车)

因此,要读取全部五个 最初由制表符分隔开的 字段,并且也利用制表 符打印它们,您可以编 程如下

$ awk '{print $1" "$2" "$3" "$4" "$5}' emp_names
46012 DULANEY EVAN MOBILE AL
46013 DURHAM JEFF MOBILE AL
46015 STEEN BILL MOBILE AL
46017 FELDMAN EVAN MOBILE AL
46018 SWIM STEVE UNKNOWN AL
46019 BOGUE ROBERT PHOENIX AZ
46021 JUNE MICAH PHOENIX AZ
46022 KANE SHERYL UNKNOWN AR
46024 WOOD WILLIAM MUNCIE IN
46026 FERGUS SARAH MUNCIE IN
46027 BUCK SARAH MUNCIE IN
46029 TUTTLE BOB MUNCIE IN
$

通过连续设置多项标准 并用管道 (|) 符号将其分隔开,您可 以一次搜索多个模式匹 配:

$ awk '/AL|IN/' emp_names
46012 DULANEY EVAN MOBILE AL
46013 DURHAM JEFF MOBILE AL
46015 STEEN BILL MOBILE AL
46017 FELDMAN EVAN MOBILE AL
46018 SWIM STEVE UNKNOWN AL
46024 WOOD WILLIAM MUNCIE IN
46026 FERGUS SARAH MUNCIE IN
46027 BUCK SARAH MUNCIE IN
46029 TUTTLE BOB MUNCIE IN
$

这样可找到每个阿拉巴 马州和印第安那州居民 的匹配记录。但是在试 图找出居住在亚利桑那 州的人时,出现了一个 问题:

$ awk '/AR/' emp_names
46019 BOGUE ROBERT PHOENIX AZ
46021 JUNE MICAH PHOENIX AZ
46022 KANE SHERYL UNKNOWN AZ
46026 FERGUS SARAH MUNCIE IN
46027 BUCK SARAH MUNCIE IN
$

员工 46026 和 46027 没有住在亚利桑那州; 但是他们的名字中包含 所搜索的字符序列。切 记,当在 AWK 中进行模式匹配时,例 如 grep、sed 或者大部分其他 Linux/Unix 命令,将在记录(行) 中的任何位置查找匹配 ,除非指定进行其他操 作。为解决这一问题, 必须将搜索与特定字段 联系起来。通过利用代 字号 (˜) 以及对特定字段的说明 ,可以达到这一目的, 如下例所示:

$ awk '$5 ˜ /AR/' emp_names
46019 BOGUE ROBERT PHOENIX AZ
46021 JUNE MICAH PHOENIX AZ
46022 KANE SHERYL UNKNOWN AZ
$

代字号(表示匹配)的 对应符号是一个前面带 有感叹号的代字号 (!˜)。 这些字符通知程序,如 果搜索序列没有出现在 指定字段中,则找出与 搜索序列相匹配的所有 行:

$ awk '$5 !˜ /AR/' names
46012 DULANEY EVAN MOBILE AL
46013 DURHAM JEFF MOBILE AL
46015 STEEN BILL MOBILE AL
46017 FELDMAN EVAN MOBILE AL
46018 SWIM STEVE UNKNOWN AL
46024 WOOD WILLIAM MUNCIE IN
46026 FERGUS SARAH MUNCIE IN
46027 BUCK SARAH MUNCIE IN
46029 TUTTLE BOB MUNCIE IN
$

在这种情况下,将显示 第五个字段中没有 AR 的所有行 — 包括两个 Sarah 条目,这两个条目确实 包含 AR,但却是在第三个 字段而不是第五个字段 中。

花括号和字段分隔符

括号字符在 AWK 命令中起着很重要的作 用。出现在括号之间的 操作指出将要发生什么 以及何时发生。当只使 用一对括号时:

{print $3,$2}

括号间的所有操作同时 发生。当使用多于一对 的括号时:

{print $3}{print $2}

执行第一组命令,在该 命令完成后执行第二组 命令。注意以下两列清 单的区别:

$ awk '{print $3,$2}' names
EVAN DULANEY
JEFF DURHAM
BILL STEEN
EVAN FELDMAN
STEVE SWIM
ROBERT BOGUE
MICAH JUNE
SHERYL KANE
WILLIAM WOOD
SARAH FERGUS
SARAH BUCK
BOB TUTTLE
$

$ awk '{print $3}{print $2}' names
EVAN
DULANEY
JEFF
DURHAM
BILL
STEEN
EVAN
FELDMAN
STEVE
SWIM
ROBERT
BOGUE
MICAH
JUNE
SHERYL
KANE
WILLIAM
WOOD
SARAH
FERGUS
SARAH
BUCK
BOB
TUTTLE
$

要利用多组括号进行重 复查找,执行第一组中 的命令直到完成为止; 然后处理第二组命令。 如果有第三组命令,则 在第二组命令完成后执 行它,以此类推。在所 生成的打印输出中,有 两个分隔的打印命令, 因此先执行第一个命令 ,随后执行第二个命令 ,这样导致每个条目显 示在两行而不是一行中 。

区分两个字段的字段分 隔符不一定始终是空格 ;它可以是任何可识别 的字符。为进行演示, 假定 emp_names 文件利用冒号而不是制 表符来分隔字段:

$ cat emp_names
46012:DULA NEY:EVAN:M OBILE:AL
46013:DURH AM:JEFF:MO BILE:AL
46015:STEE N:BILL:MOB ILE:AL
46017:FELD MAN:EVAN:M OBILE:AL
46018:SWIM :STEVE:UNK NOWN:AL
46019:BOGU E:ROBERT:P HOENIX:AZ
46021:JUNE :MICAH:PHO ENIX:AZ
46022:KANE :SHERYL:UN KNOWN:AR
46024:WOOD :WILLIAM:M UNCIE:IN
46026:FERG US:SARAH:M UNCIE:IN
46027:BUCK :SARAH:MUN CIE:IN
46029:TUTT LE:BOB:MUN CIE:IN
$

如果试图通过指定所需 要的第二个字段来打印 姓氏

$ awk '{print $2}' emp_names

您最后会得到十二个空 行。因为文件中没有空 格,除了第一个字段之 外没有可认别的字段。 为解决这一问题,必须 通知 AWK 是空格之外的另一个字 符作为分隔符,有两种 方法可通知 AWK 使用新的字段分隔符: 使用命令行参数 -F,或在程序中指定 变量 FS。两种方法的效果 相同,只有一种例外情 况,如下例所示:

$ awk '{FS=":"}{ print $2}' emp_names

DURHAM
STEEN
FELDMAN
SWIM
BOGUE
JUNE
KANE
WOOD
FERGUS
BUCK
TUTTLE
$

$ awk -F: '{print $2}' emp_names
DULANEY
DURHAM
STEEN
FELDMAN
SWIM
BOGUE
JUNE
KANE
WOOD
FERGUS
BUCK
TUTTLE
$

在第一个命令中,头一 条记录返回不正确的空 行,而其他结果正确。 直到读取第二条记录时 ,才识别字段分隔符并 正确地执行。通过使用 BEGIN 语句可以纠正这一缺点 (在后文详述)。-F 的功能非常类似于 BEGIN,能够正确 地读取第一条记录并按 要求执行。

在本文开始处我曾提到 ,默认的显示/输出字 段分隔符是空格。通过 使用输出字段分隔符 (OFS) 变量,可以在程序中更 改此特性。例如,要读 取文件(由冒号分隔) 并以短划线显示,则命 令是

$ awk -F":" '{OFS="-"} {print $1,$2,$3,$ 4,$5}' emp_names
46012-DULA NEY-EVAN-M OBILE-AL
46013-DURH AM-JEFF-MO BILE-AL
46015-STEE N-BILL-MOB ILE-AL
46017-FELD MAN-EVAN-M OBILE-AL
46018-SWIM -STEVE-UNK NOWN-AL
46019-BOGU E-ROBERT-P HOENIX-AZ
46021-JUNE -MICAH-PHO ENIX-AZ
46022-KANE -SHERYL-UN KNOWN-AR
46024-WOOD -WILLIAM-M UNCIE-IN
46026-FERG US-SARAH-M UNCIE-IN
46027-BUCK -SARAH-MUN CIE-IN
46029-TUTT LE-BOB-MUN CIE-IN
$

FS 和 OFS 是(输入)字段分隔符 和输出字段分隔符,它 们只是一对可以在 AWK 实用工具中使用的变量 。例如,要在打印时为 每行编号,可以采用以 下方式使用 NR 变量:

$ awk -F":" '{print NR,$1,$2,$ 3}' emp_names
1 46012 DULANEY EVAN
2 46013 DURHAM JEFF
3 46015 STEEN BILL
4 46017 FELDMAN EVAN
5 46018 SWIM STEVE
6 46019 BOGUE ROBERT
7 46021 JUNE MICAH
8 46022 KANE SHERYL
9 46024 WOOD WILLIAM
10 46026 FERGUS SARAH
11 46027 BUCK SARAH
12 46029 TUTTLE BOB
$

找出员工号码处于 46012 和 46015 之间的所有行:

$ awk -F":" '/4601[2-5 ]/' emp_names
46012 DULANEY EVAN MOBILE AL
46013 DURHAM JEFF MOBILE AL
46015 STEEN BILL MOBILE AL
$

添加文本

可以按照添加控制序列 或其他字符的相同方式 将文本添加到显示中。 例如,要将分隔符从空 格改为冒号,则命令是

awk '{print $1":"$2":" $3":"$4":" $5}' emp_names > new_emp_na mes

在这种情况下,字符 (:) 包含在引号 ("/") 中,它被添加到每个字 段之间。在引号之间的 值可以是任何内容。例 如,创建一个关于居住 在阿拉巴马州的员工的 外观类似数据库的显示 :

$ awk '$5 ~ /AL/ {print "NAME: "$2", "$3" CITY-STATE :
"$4", "$5" "}' emp_names

NAME: DULANEY, EVAN
CITY-STATE : MOBILE, AL

NAME: DURHAM, JEFF
CITY-STATE : MOBILE, AL

NAME: STEEN, BILL
CITY-STATE : MOBILE, AL

NAME: FELDMAN, EVAN
CITY-STATE : MOBILE, AL

NAME: SWIM, STEVE
CITY-STATE : UNKNOWN, AL
$

数学操作

AWK 除了提供文本功能,还 提供全部范围的算术操 作符,包括以下符号:

+ 将数字相加
- 减
* 乘
/ 除
^ 执行指数运算
% 提供模
++ 将变量值加一
+= 将其他操作的结果分配 给变量
— 将变量减一
-= 将减法操作的结果分配 给变量
*= 分配乘法操作的结果
/= 分配除法操作的结果
%= 分配求模操作的结果

例如,假定您的机器上 存在以下的文件,详细 地列出硬件商店中的物 品:

$ cat inventory
hammers 5 7.99
drills 2 29.99
punches 7 3.59
drifts 2 4.09
bits 55 1.19
saws 123 14.99
nails 800 .19
screws 80 .29
brads 100 .24
$

第一项业务定单是通过 将第二个字段(数量) 的值乘以第三个字段( 价格)的值,计算每种 物品的库存价值:

$ awk '{print $1,"QTY: "$2,"PRICE : "$3,"TOTAL : "$2*$3}' inventory
hammers QTY: 5 PRICE: 7.99 TOTAL: 39.95
drills QTY: 2 PRICE: 29.99 TOTAL: 59.98
punches QTY: 7 PRICE: 3.59 TOTAL: 25.13
drifts QTY: 2 PRICE: 4.09 TOTAL: 8.18
bits QTY: 55 PRICE: 1.19 TOTAL: 65.45
saws QTY: 123 PRICE: 14.99 TOTAL: 1843.77
nails QTY: 800 PRICE: .19 TOTAL: 152
screws QTY: 80 PRICE: .29 TOTAL: 23.2
brads QTY: 100 PRICE: .24 TOTAL: 24
$

如果这些行本身并不重 要,您只是希望确定商 店中有多少件物品,则 可以分配一个普通变量 ,按照每条记录中的物 品数量增加:

$ awk '{x=x+$2} {print x}' inventory
5
7
14
16
71
194
994
1074
1174
$

根据这一数据,商店中 有 1174 件物品。第一次执行时 ,变量 x 没有值,因此它采用第 一行第二个字段的值。 第二次执行时,它保留 了第一行的值并加上第 二行的值,以此类推, 直到达到累计的总合。

可以应用相同的过程来 确定现有库存的总价值 :

$ awk '{x=x+($2* $3)} {print x}' inventory
39.95
99.93
125.06
133.24
198.69
2042.46
2194.46
2217.66
2241.66
$

因此,1174 件物品的价值是 $2,241.66。 虽然这一过程可以获得 总计值,但它的外观很 差,需要加工成实际的 报表。利用一些附加项 ,很容易使显示变得更 整洁:

$ awk '{x=x+($2* $3)}{print $1,"QTY: "$2,"PRICE : "$3,"TOTAL : "$2*$3,"BA L: "x}' inventory
hammers QTY: 5 PRICE: 7.99 TOTAL: 39.95 BAL: 39.95
drills QTY: 2 PRICE: 29.99 TOTAL: 59.98 BAL: 99.93
punches QTY: 7 PRICE: 3.59 TOTAL: 25.13 BAL: 125.06
drifts QTY: 2 PRICE: 4.09 TOTAL: 8.18 BAL: 133.24
bits QTY: 55 PRICE: 1.19 TOTAL: 65.45 BAL: 198.69
saws QTY: 123 PRICE: 14.99 TOTAL: 1843.77 BAL: 2042.46
nails QTY: 800 PRICE: .19 TOTAL: 152 BAL: 2194.46
screws QTY: 80 PRICE: .29 TOTAL: 23.2 BAL: 2217.66
brads QTY: 100 PRICE: .24 TOTAL: 24 BAL: 2241.66
$

该过程提供了每条记录 的清单,同时将总价值 分配给库存值,并保持 商店资产的运作平衡。

BEGIN 和 END

使用 BEGIN 和 END 语句可以分别指定在处 理实际开始之前或者完 成之后进行操作。BE GIN 语句最常用于建立变量 或显示标题。另一方面 ,END 语句可用于在程序结束 后继续进行处理。

在前面的示例中,利用 以下例程生成了物品的 总价值:

awk '{x=x+($2* $3)} {print x}' inventory

该例程在运行总计累加 时显示了文件中的每一 行。没有其他方法可以 指定它,而不让在每一 行进行打印也导致它始 终不打印出来。但是, 利用 END 语句可以避免这一问题 :

$ awk '{x=x+($2* $3)} END {print "Total Value of Inventory: "x}' inventory
Total Value of Inventory: 2241.66
$

定义了变量 x,它对每一行进行处 理;但是,在所有处理 完成之前不会生成显示 。尽管可以作为独立例 程使用,它也可以置入 到先前的代码列表,添 加更多信息并生成更完 整的报表:

$ awk '{x=x+($2* $3)} {print $1,"QTY: "$2,"PRICE :
"$3,"TOTAL : "$2*$3} END {print "Total Value of Inventory: " x}' inventory

hammers QTY: 5 PRICE: 7.99 TOTAL: 39.95
drills QTY: 2 PRICE: 29.99 TOTAL: 59.98
punches QTY: 7 PRICE: 3.59 TOTAL: 25.13
drifts QTY: 2 PRICE: 4.09 TOTAL: 8.18
bits QTY: 55 PRICE: 1.19 TOTAL: 65.45
saws QTY: 123 PRICE: 14.99 TOTAL: 1843.77
nails QTY: 800 PRICE: .19 TOTAL: 152
screws QTY: 80 PRICE: .29 TOTAL: 23.2
brads QTY: 100 PRICE: .24 TOTAL: 24
Total Value of Inventory: 2241.66
$

BEGIN 命令与 END 的工作方式相同,但它 建立了那些需要在完成 其他工作之前所做的项 目。该过程最常见的目 的是创建报表的标题。 此例程的语法类似于

$ awk 'BEGIN {print "ITEM QUANTITY PRICE TOTAL"}'

输入、输出和源文件

AWK 工具可以从文件中读取 其输入,正如在此之前 所有示例所做的那样, 它也可以从其他命令的 输出中获取输入。例如 :

$ sort emp_names | awk '{print $3,$2}'

awk 命令的输入是排序操作 的输出。除了 sort,还可以使用 任何其他的 Linux 命令 — 例如 grep。该过程允许 您在离开所选定字段前 对文件执行其他操作。

类似于解释程序,AW K 使用输出改向操作符 > 和 >> 将其输出放入文件中而 不是标准输出设备。这 些符号的作用类似于它 们在解释程序中的对应 符号,因此 > 在不存在文件时创建文 件,而 >> 追加到现有文件的尾部 。请看以下的示例:

$ awk '{print NR, $1 ) > "/tmp/file z" }' emp_names
$ cat /tmp/filez
1 46012
2 46013
3 46015
4 46017
5 46018
6 46019
7 46021
8 46022
9 46024
10 46026
11 46027
12 46029
$

检查该语句的语法,您 会看到输出改向是在打 印语句完成后进行的。 必须将文件名包含在引 号中,否则它只是一个 未初始化的 AWK 变量,而将指令联接起 来会在 AWK 中产生错误。(如果不 正确地使用改向符号, 则 AWK 无法了解该符号意味着 “改向”还是一个关系 操作符。)

在 AWK 中输出到管道也类似于 解释程序中所实现的相 同操作。要将打印命令 的输出发送到管道中, 可以在打印命令后附加 管道符号以及命令的名 称,如下所示:

$ awk '{ print $2 | "sort" }' emp_names
BOGUE
BUCK
DULANEY
DURHAM
FELDMAN
FERGUS
JUNE
KANE
STEEN
SWIM
TUTTLE
WOOD
$

这是输出改向的情况, 必须将命令包含在引号 中,而管道的名称是被 执行命令的名称。

AWK 所使用的命令可以来自 两个地方。首先,可以 在命令行中指定它们, 如示例中所示。其次, 它们可以由源文件提供 。如果是这种情况,通 过 -f 选项将这种情况向 AWK 发出警告。演示如下:

$ cat awklist
{print $3,$2}
{print $4,$5," "}
$

$ awk -f awklist emp_names
EVAN DULANEY
MOBILE AL

JEFF DURHAM
MOBILE AL

BILL STEEN
MOBILE AL

EVAN FELDMAN
MOBILE AL

STEVE SWIM
UNKNOWN AL

ROBERT BOGUE
PHOENIX AZ

MICAH JUNE
PHOENIX AZ

SHERYL KANE
UNKNOWN AR

WILLIAM WOOD
MUNCIE IN

SARAH FERGUS
MUNCIE IN

SARAH BUCK
MUNCIE IN

BOB TUTTLE
MUNCIE IN

$

注意,在源文件中的任 何地方或者在命令行中 调用它时,不使用单引 号。单引号只用于区别 命令行中的命令与文件 名称。

如果简单的输出不能处 理您的程序中所需要的 复杂信息,则可以尝试 由 printf 命令获得的更加复杂的 输出,其语法是

printf( format, value, value ...)

该语法类似于 C 语言中的 printf 命令,而格式的规格是 相同的。通过插入一项 定义如何打印数值的规 格,可以定义该格式。 格式规格包含一个跟有 字母的 %。类似于打印命令, printf 不必包含在圆括号中, 但是可以认为使用圆括 号是一种良好的习惯。

下表列出 printf 命令提供的各种规格。

规格 说明
%c 打印单个 ASCII 字符
%d 打印十进制数
%e 打印数字的科学计数表 示
%f 打印浮点表示
%g 打印 %e 或 %f;两种方式都更简 短
%o 打印无符号的八进制数
s 打印 ASCII 字符串
%x 打印无符号的十六进制 数
%% 打印百分号;不执行转 换

可以在 % 与字符之间提供某些附 加的格式化参数。这些 参数进一步改进数值的 打印方式:

参数 说明
- 将字段中的表达式向左 对齐
,width 根据需要将字段补齐到 指定宽度(前导零使用 零将字段补齐)
.prec 小数点右面数字的最大 字符串宽度或最大数量

printf 命令能够控制并将数值 从一种格式转换为另一 种格式。当需要打印变 量的值时,只需提供一 种规格,指示 printf 如何打印信息(通常包 含在双引号中)即可。 必须为每个传递到 printf 的变量包含一个规格参 数;如果包含过少的参 数,则 printf 不会打印所有的数值。

处理错误

AWK 工具报告所发生错误的 方式很令人恼火。一个 错误会阻碍任何操作的 进行,所提供的错误信 息非常含混不清:

awk: syntax error near line 2
awk: bailing out near line 2

您可能会花几小时的时 间查看第 2 行,试图找出它为什么 阻碍程序运行;这就是 支持使用源文件的一个 有力论据。

切记有两条规则可以帮 助您避免出现语法错误 :

1. 确保命令位于括号中, 而括号位于单引号中。 没有使用这些字符之一 必然导致程序无法运行 。

2. 搜索命令需要位于斜线 之间。要找出住在印第 安那州的员工,您必须 使用“/IN/”而不 是“IN”。

结论

尽管 AWK 完全代表另外的含意, 但它应该是管理员智能 工具包的首字母缩写。 连同 SED 一起,AWK 实用工具是 Linux 管理员所拥有的功能最 强大和灵活的工具之一 。通过了解其语言的一 些特性,您可以开辟出 能够简化任务的领域, 否则这些任务将会是非 常费时和困难的。