Chinaunix首页 | 论坛 | 博客
  • 博客访问: 233960
  • 博文数量: 52
  • 博客积分: 3010
  • 博客等级: 中校
  • 技术积分: 731
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-25 17:46
文章分类
文章存档

2009年(13)

2008年(39)

我的朋友

分类: LINUX

2009-05-17 18:30:08

添加文本

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

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

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

$ awk '$5 ~ /AL/ {print "NAME: "$2", "$3"\nCITY-STATE:
  "$4", "$5"\n"}' 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,"BAL: "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
$

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

BEGINEND

使用 BEGINEND 语句可以分别指定在处理实际开始之前或者完成之后进行操作。BEGIN 语句最常用于建立变量或显示标题。另一方面,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。该过程允许您在离开所选定字段前对文件执行其他操作。

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

$ awk '{print NR, $1 ) > "/tmp/filez" }' 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,"\n"}
$

$ 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 管理员所拥有的功能最强大和灵活的工具之一。通过了解其语言的一些特性,您可以开辟出能够简化任务的领域,否则这些任务将会是非常费时和困难的。

阅读(1363) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~