3.9. 使用 Awk
使用 Awk
像 sed 一样, awk 对输入的每一行执行一系列的指令。你可以在命令行上指定指令或创建一个脚本文件。
运行 awk
对命令行而言,语法如下:
awk 'instructions' files
输入是从一个或多个文件或标准输入中,每次读取一行。指令必须被单引号包裹来保护他们不被 shell 破坏。指令几乎总是包括大括号和/或美元符号,这些符号都会被 shell 解析为特殊字符。多行命令能像前面 sed 那样被键入:用分号分隔命令或使用 Bourne shell 的多行输入能力。
Awk 程序通常放在他们能被测试和修改的文件中。使用一个脚本文件调用 awk 的语法如下:
awk -f script files
-f 选项的作用和 sed 中的是一样的。
虽然 awk 的指令和 sed 有一样的结构,都由模式和步骤组成,但步骤和 sed 的步骤是很不一样的。这就是 awk 看起来不像一个编辑器,而更像一门编程语言的地方。语句和函数替换了一个或两个字符的命令序列。比如,你使用 print 语句来打印出一个表达式的值或打印出当前输入行的内容。
通常情况下,awk将每一个输入行解释为一个记录,在那一行上用空格或 tabs 分隔的每一个单词解释为一个字段。(这些默认规定都可以被更改。)一个或多个连续的空格或 tabs 被记作一个分隔符。不管是在模式还是在步骤中,awk 都允许你引用这些字段。 $0 代表整个输入行。$1, $2, ... 代表的是输入行上的各个字段。Awk 先拆分输入记录,再应用脚本。让我们看一些例子,使用名为 list 的样本输入文件。
第一个例子包含了一个打印输入文件每行第一个字段的简单指令。
➜ ch02 git:(daily) ✗ awk '{print $1}' list
John
Alice
Orville
Terry
Eric
Hubert
Amy
Sal
$1 引用的是每一个输入行上的第一个字段的值。因为没有指定模式,print 语句应用于所有行。在下一个例子中,指定了一个 “/MA/” 的模式,但没有步骤。(当没有步骤时)默认的动作是打印匹配模式的每一行。
➜ ch02 git:(daily) ✗ awk '/MA/' list
John Daggett, 341 King Road, Plymouth MA
Eric Adams, 20 Post Road, Sudbury MA
Sal Carpenter, 73 6th Street, Boston MA
打印了三行。如第一章中提到的,一个 awk 程序能使用得更像一个查询语言——从一个文件中提取有用信息。我们可以说模式对即将被包含在报告中的记录的选择设置了一个条件,也就是说他们必须包含字符串 “MA”。现在我们也可以指定一行记录的哪个部分被包含在报告中。下面的例子使用了一个 print 语句来限制输出为每个记录的第一个字段。
➜ ch02 git:(daily) ✗ awk '/MA/ {print $1}' list
John
Eric
Sal
如果我们试着大声朗读会有助于理解上面的指令:打印包含字符串 “MA” 的每一行的第一个单词。我们能说“单词”,因为默认情况下,awk 使用空格或 tab 作为字段分割符,将输入分隔为几个字段。
在下面的例子中,我们使用 -F 选项来改变字段分隔符为一个冒号。这使得我们可以提取三个字段中的任何一个:全名,街道地址,或城市和州。
➜ ch02 git:(daily) ✗ awk -F, '/MA/ {print $1}' list
John Daggett
Eric Adams
Sal Carpenter
不要将改变字段分隔符的 -F 选项与指定脚本名称的 -f 选项混淆了。
在下面的例子中,我们将每个字段打印在单独一行上。多行命令被分号分隔。
➜ ch02 git:(daily) ✗ awk -F, '{print $1; print $2; print $3}' list
John Daggett
341 King Road
Plymouth MA
Alice Ford
22 East Broadway
Richmond VA
Orville Thomas
11345 Oak Bridge Road
Tulsa OK
Terry Kalkas
402 Lans Road
Beaver Falls PA
Eric Adams
20 Post Road
Sudbury MA
Hubert Sims
328A Brook Road
Roanoke VA
Amy Wilde
334 Bayshore Pkwy
Mountain View CA
Sal Carpenter
73 6th Street
Boston MA
我们使用 sed 的例子改变了输入数据的内容。我们使用 awk 的例子重新排列了内容。在上面的 awk 例子中,注意到前置空格现在是怎样被认为是第二和第三个字段的一部分——那是因为我们使用了逗号作为分隔符,所以说空格就作为字段的内容的一部分。
错误信息
当在你的程序中遇到错误时,awk每个实现都给了不同的错误信息。因此我们不会引用一个特定版本的信息。当有问题时是明显的。信息能被下面三个原因所导致:
-
没有用大括号包含包裹一个步骤。
➜ ch02 git:(daily) ✗ awk -F, '{print $1; print $2; print $3' list awk: syntax error at source line 1 context is {print $1; print $2; print >>> $3 <<< awk: illegal statement at source line 1 missing }
-
没有用单引号包裹指令。
➜ ch02 git:(daily) ✗ awk -F, '{print $1; print $2; print $3 list quote>
-
没有用斜杠包裹正则表达式。
➜ ch02 git:(daily) ✗ awk -F, '/MA {print $1}' list awk: non-terminated regular expression MA {print ... at source line 1 context is /MA {print >>> $1} <<<
选项小结
表格 2-2 awk 命令行选项
-v 这个选项是在命令行上指定参数,将在第七章《编写 awk 脚本》中被讨论。
推荐文章: