[关闭]
@1405010304geshuaishuai 2017-07-28T11:50:56.000000Z 字数 10975 阅读 784

正则表达式之查找与替换

正则表达式 查找与替换 shell


3.1 查找文本

3.1.1 简单的grep

grep最简单的用法就是使用固定字符串:

  1. $ who | grep -F root

范例中使用-F选项,以查找固定字符串root。事实上,只要匹配的模式里未含有正则表达式的meta字符(metacharacter),则grep默认行为模式就等同于使用了-F。

3.2 正则表达式

主要提供有关正则表达式构造与匹配方式的概述。特别会提及POSIX BRE与ERE构造,因为它们想要将大部分UNIX工具里的两种正则表达式基本风格(flavor)加以正式化。

3.2.1 什么是正则表达式

正则表达式是一种表示方式,让你可以查找匹配特定准则的文本。
正则表达式是由两个基本组成部分所建立:一般字符与特殊字符。

字符 模式含义
\ 通常用于关闭后续字符的特殊含义
. 匹配任何单个的字符,但NUL除外。独立程序也可以不允许匹配换行符
* 匹配在它之前的任何数目(或没有)的单个字符
^ 匹配紧接着的正则表达式,在行或字符串的起始处
$ 匹配前面的正则表达式,在字符串或行结尾处
[...] 方括号表达式(bracket expression),匹配方括号内的任一字符。连字符(-)指的是连续字符的范围。^符号置于方括号里第一个字符则有反向含义:指的是匹配不在列表内(方括号内)的任何字符。作为首字符的一个连字符或是结束方括号(]),则被视为列表的一部分。
\{n,m\} 区间表达式(interval expression),匹配在它前面的单个字符重现(occurrences)的次数区间。\ {n\ }指的是重现n次;\ {n,\ } 则为至少重现(oocurrences)n次,而\ {n,m\ }为重现n至m次。
\ ( \ ) 将\ (与\ )间的模式存储在特殊的“保留空间(holding space)”。最多可以将9个独立的子模式(subpattern)存储在单个模式中。匹配于子模式的文本,可通过转义序列(escape sequences) \1至\9,被重复使用在相同模式里。例如\ (ab\ ).* \1,指的是匹配于ab组合的两次重现,中间可存在任何数目的字符。
\n 重复在\ (与\ )方括号内第n个子模式至此点的模式。n为1至9的数字, 1为由左开始。
{n,m} 与先前提及的\ {n,m\ }一样,只不过方括号前没有反斜杠。
+ 匹配前面正则表达式的一个或多个实例。
? 匹配前面正则表达式的零个或一个实例。
I 匹配于I符号前或后的正则表达式。
( ) 匹配于方括号括起来的正则表达式群。

3.2.1.1 POSIX 方括号表达式

在POSIX的标准下,现在叫做方括号表达式(bracket expression).在方括号表达式内除了字符之外(例如z、;等等)之外,另有额外的组成部分,包括:
字符集(Character class)
以[:与:]将关键字组合括起来的POSIX字符集。关键字描述各种不同的字符集,例如英文字母字符、控制字符等,见下表。
排序符号(Collating symbol)
排序符号指的是将多个字符序列视为一个单位。它使用[.与.]将字符组合括起来。
等价字符集(Equivalence class)
等价字符集列出的应视为等值的一组字符。以[=与=]括住。
这三种构造都必须使用方括号括住表达式。
表3-3:POSIX字符集

类别 匹配字符
[:alnum:] 数字字符
[:alpha:] 字母字符
[:blank:] 空格(space)与定位(tab)字符
[:cntrl:] 控制字符
[:digit:] 数字字符
[:graph:] 非空格(nonspace)字符
[:lower:] 小写字母字符
[:print:] 可显示的字符
[:punct:] 标点符号字符
[:space:] 空白(whitespace)字符
[:upper:] 大写字母字符
[:xdigit:] 十六进制数字

3.2.2 基本正则表达式

BRE是由多个组成部分所构建,一开始提供数种匹配单个字符的方式,而后又结合额外的meta字符,进行多字符匹配。

3.2.2.1 匹配单个字符

注意:
1.在方括号的表达式里,^放在字首表示是取反(complement)的意思;也就是说,不再 方括号列表里的任意字符。所以[^aeiouy]表示的就是所有小写元音字母以外的任何字符。例如:大写元音字母、所有辅音字母、数字、标点符号等。

2.将所有要匹配的字母全列出来是一件无聊又麻烦的事情,例如[0123456789]指所有数字,或[0123456789abcdefABCDEF]表示所有十六进制的数字。因此,方括号表达式可以包括字符的范围。像前面提过的两个例子,就可以分别以[0-9]与[0-9a-fA-F]表示。

排序(collating)是指给予成组的项目排列顺序的操作。由[.与.]括起来。
等价字符集(equivalence class)用来让不同字符在匹配时视为相同字符。等价字符集类别名称以[=与=]括起来。
最后一个特殊zu'che组成部分:字符集,它表示字符的类别,例如数字、小写与大写字母、标点符号、空白(whitespace)等。这些类别名称定义于[:与:]之间。

注意:在方括号表达式中,左右其他的meta字符都会失去其特殊含义。所以[*.]匹配于字面上的星号、反斜杠以及句点。要让]进入该集合,可以将它放在列表的最前面:[]*.],将]增加至词列表中。要让减号字符进入该集合,也请将它放到列表最前端:[-*.]。若你需要右方括号与减号两者进入列表,请将右方括号放到第一个字符、减号放到最后一个字符:[]*.-]。

POSIX明确陈述:NUL字符(数值的零)不需要时可匹配的。这个字符在C语言中是用来指出字符串结尾,而POSIX标准则希望让它直接了当的,通过正规C字符串的使用实现其功能。

3.2.2.2 后向引用

BRE提供一种叫向后引用(backreferences)的机制,指的是“匹配于正则表达式匹配的先前的部分”。使用后向引用的步骤有两个。第一步是将子表达式包围在 \ (与\ )里;单个模式里可包括至多9个子表达式,且可为嵌套结构。

下一步是在同一模式之后使用\digit,digit指的是介于1至9的数字,指的是“匹配于第n个前方括号内子表达式匹配成功的字符”。举例如下:

模式 匹配成功
\ (ab \ ) \ (cd \ )[def]*\2\1 abcdcdab,abcdeeecdab,abcdddeeffcdab
\ (why\ ).*\1 一行里重现两个why
\ ([[:alpha:]] [[:alnum:]]*\ )=\1 简易C/C++赋值语句

后向引用在寻找重复字以及匹配引号时特别好用:
\ ([" ']\ ).* \1 匹配以单引号或是双引号括起来的字,例如'foo'或"bar"

3.2.2.3 单个表达式匹配多字符

匹配多字符最简单的方法就是把它们一个接一个(连接)列出来,所以正则表达式ab匹配ab,..(两个点号)匹配任意两个字符,而[[:upper:]][[:lower:]]则匹配于任意一个大写字符,后面接着任意一个小写字符。
虽然.(点号)meta字符与方括号表达式都提供一次匹配一个字符的很好方式,但正则表达式真正强而有力的功能,其实是在修饰符(modifier)meta字符的使用上。
最常用的的修饰符为星号(*),表示“匹配0个或多个前面的单个字符”。因此,ab*c表示的是“匹配1个a、0或多个b字符以及c”。这个正则表达式匹配的有ac、abc、abbc、abbbc等。
*修饰符最好用的,但它没有限制,你不能用*表示“匹配三个字符,而不是四个字符”。而要使用一个复杂的方括号表示,表明所需的匹配次数。区间表达式(interval expression)可以解决这类问题。

  1. \ {n \ } 前置正则表达式所得结果重现n
  2. \ {n, \ } 前置正则表达式所得结果重现至少n
  3. \ {n,m \ } 前置正则表达式所得结果重现nm

有了区间表达式,要表达像“重现5个a”或“重现10到42个q”就变得很简单了,这两项分别是: a\ {5 \ }与 q \ {10,42\ }。

3.2.2.4 文本匹配锚点

还有两个meta字符是脱字符号(^)与货币符号($),它们叫做锚点(anchor),因为其用途在限制正则表达式匹配时,针对要被匹配字符串得开始或结尾处进行匹配(^在此处得用法与方括号表达式里得完全不同)。
^与$也可同时使用,这种情况是将括起来得正则表达式匹配整个字符串(或行)。有时^$这样得简易正则表达式也很有好用,它可以用来匹配空得字符串或行列。
扩展文件(expended file)里头时长包含得空白或空行通常会比原始码更多,因此要排除空行只要:

  1. $ cc -E foo.c | grep -v '^$' >foo.out 预先删除空行

grep 加上 -v选项可以用来显示所有不匹配于模式的行,使用上面的做法,便能够过滤掉文件里的空(empty)行。

3.2.2.5 BRE运算符优先级

表3-5:BRE运算符优先级,由高至低

运算符 表示意义
[..] [==] [::] 用于字符排序的方括号符号
\metacharacter 转义的meta字符
[] 方括号表达式
\ ( \ ) \digit 子表达式与后向引用
    \ { \ }
前置单个字符重现的正则表达式
无符号(no symbol) 连续
^ $ 锚点(Anchors)

3.2.3扩展正则表达式

ERE拥有比基本正则表达式更多的功能。

3.2.3.1 匹配单个字符

较有名的一个例外出现在awk里:其\符号在方括号表达式内表示其他的含义。因此,如需匹配左方括号、连字符、右方括号或是反斜杠,你应该用[\ [\ -\ ] \ \ ]。

3.2.3.2 后向引用不存在

ERE里没有后向引用的。圆括号在ERE里具特殊含义,但和BRE里的使用又有所不同,在ERE里,\ (与\ )匹配的是字面上的左括号与右括号。

3.2.2.3 匹配单个表达式与多个正则表达式

ERE在匹配多字符这方面,与BRE又很明显的不同。不过,在*的处理上和BRE是相同的。
注意:*作为ERE的第一个字符是“未定义的”,而在BRE中它是指“符合字面的*”

区间表达式可用于ERE中,但它们是写在花括号里({}),且不需要前置反斜杠字符。因此我们先前的例子“要刚好重现5个a”以及“重现10个至42个q”,写法分别为:a{5}与q{10,42}。而\ { 与 \ }则可用以匹配字面上的花括号,当在ERE里{找不到匹配的}时,POSIX特意保留其含义为“未定义(undefined)状态”。
ERE另有两个meta字符,可更细腻地处理匹配控制:
? 匹配于0个或一个前置正则表达式
+ 匹配于1个或多个前置正则表达式

3.2.3.4 交替

使用交替(alternation)运算符,即垂直地一条线,或称为管道字符(|)。
|字符ERE运算符里优先级最低的。因此,左边会一路扩展到运算符的左边,一直到一个前置|的字符,或者时到另一个正则表达式的起始。同样地,|的右边也是一路扩展到运算符的右边,一直到后续的|字符,或是到整个正则表达式的结尾。

3.2.3.5 分组

(why)+匹配一个或连续重复的多个why。
在必须用到交替(alternation)时,分组的功能就特别好用了(也是必需的)。它可以让你用以构建复杂并较灵活性的正则表达式,举例来说[Tt]he (CPU|computer) is 指的就是: 在The(或the)与is之间,含有CPU或computer的句子。要特别注意的一点是,圆括号在这里是meta字符,而非要匹配的输入文本。
举例:(((read|write)[[:space:]]*)+的正则表达式的意思。
结论是:这个单个正则表达式是用以匹配多个连续出现的read和write,且中间可能被空白符隔开。
在[[:space:]]之后使用*是一种判断调用(judgement call)。使用一个*而非+,此时可以匹配在行(或字符串)结尾的单词。但也可以匹配中间完全没有空白的单词。运用正则表达式时常会需要用到这样的判断调用(judgment call)。

当你将交替(alternation)操作结合^与$锚点字符使用时,分组就非常好用了。由于|为所有运算符中优先级最低的,因此正则表达式^abcd|efgh$意思是“匹配字符串的起始处是否有abcd,或者字符串结尾处是否有efgh”,这个^(abcd|efgh)$不一样,后者表示的是“找一个正是abcd或正是efgh的字符串”。

3.2.3.6 停驻文本匹配

^与$在这里表示的意义与BRE里的相同:将正则表达式停驻在文本字符串(或行)的起始或结尾处。不过有个明显不同的地方就是:在ERE里,^与$永远是meta字符。

3.2.3.7 ERE运算符的优先级

运算符 含义
[..] [==] [::] 用于字符对应的方括号符号
\metacharacter 转义的meta字符
[] 方括号表达式
() 分组
* + ? {} 重复前置的正则表达式
无符号(no symbol) 连续字符
^ $ 锚点(Anchors)
I 交替(Alternation)

3.2.4 正则表达式的扩展

最常见的扩展为\ <与 \ >运算符,分别匹配“单词(word)”的开头与结尾。单词是由字母,数字及下划线组成的。我们称这类字符为单词组成(word-constituent)。
表3-7:额外的GNU正则表达式运算符

运算符 含义
\ w 匹配任何单词组成字符,等同于[[:alnum:]_]
\ W 匹配任何非单词组成的字符,等同于[^[:alnum:]_]
\ < \ > 匹配单词的起始与结尾。
\ b 匹配单词的起始与结尾所找到的空字符串。这是\ <与\ >运算符的结合
\ B 匹配两个单词组成字符之间的空字符串
\ ' \ ` 分别匹配emacs缓冲区的开始与结尾。GNU程序(还有emacs)通常将它们视为^与$同义

3.2.5 程序与正则表达式

从略

3.2.6 在文本文件里进行替换

一般来说,执行文本替换的正确程序应该是sed--流编辑器(Stream Editor) 。sed的涉及就是用来以批处理的方式而不是交互的方式来编辑文件。

3.2.7 基本用法

你可能会常在管道(pipeline)中间使用sed,以执行替换操作。做法就是使用s命令--要求正则表达式寻找,用替代文本(replacement text)替换匹配的文本,以及可选用的标志:

  1. sed 's/:.*//' /etc/passwd | 删除第一个冒号之后的所有东西
  2. sort -u 排序列表并删除重复部分

在这里,/字符扮演定界符(delimiter)的角色,从而分隔正则表达式与替代文本(replacement text)。在本例中,替代文本是空的(空字符串 null string),实际上会有效地删除匹配地文本。

  1. find /home/tolstoy -type d -print |寻找所有目录
  2. sed 's;/home/tolstoy/;/home/lt/;' |修改名称;注意:这里使用分号作为定界符
  3. sed 's/^/mkdir /' |插入mkdir命令
  4. sh -x |以Shell跟踪模式执行

上述脚本是将/home/tolstoy目录结构建立一份副本在/home/lt下(可能是为备份而做的准备)。(在本例中它地输出是/home/tolstoy底下的目录名称列表:一行一个目录。)这个脚本使用了产生命令(generating command)的手法,使命令内容成为Shell的输入。这是一个功能很强且常见的技巧。

3.2.7.1 替换细节

sed 了解后向引用,而且它们还能用于替换文本中,以表示“从这里开始替换成匹配第n个圆括号里子表达式的文本”:

  1. $ echo /home/tolstoy/ | sed 's;\(/home\)/tolstoy/;\1/lt/;'

最后说明的是:&在替代文本里表示的意思是“从此点开始替代成匹配于正则表达式的整个文本”。举例来说,假设处理Atlanta Chamber of Commerce这串文本,想要在广告册中修改所有对该城市的描述:

  1. mv atlga.xml atlga.xml.old
  2. sed 's/Atlanta/&, the capital of the South/' < atlga.xml.old > atlga.xml

这个脚本会存储一份原始广告小册的备份,做这类操作绝对有必要。

如果要在替代文本里使用&字符的字面意义,请使用反斜杠转义它。例如,下面的小脚本可以转换DocBook/XML文件里字面上的反斜杠,将其转换为DocBook里对应的&bsol:

  1. sed 's/\\/\&bsol;/g'

在s命令里以g结尾表示的是:全局性(global),意即以“替代文本取代正则表达式中每一个匹配的”。如果没有设置g,sed只会取代第一个匹配的。这里来比较看看有没有设置g产生的结果。
sed

给予sed多个命令是比较容易的。在命令行上,这是通过-e选项的方式来完成。每一个编辑命令都使用一个-e选项:

  1. $ sed -e 's/foo/bar/g' -e 's/chicken/cow/g' myfile.xml > myfile2.xml

有时,将编辑命令全放进一个脚本里,再使用sed搭配-f选项会更好:

  1. $ cat fixup.sed
  2. s/foo/bar/g
  3. s/chicken/cow/g
  4. s/draft animal/horse/g
  5. ...
  6. $ sed -f fixup.sed myfile.xml > myfile2.xml

POSIX也允许使用分号将同一行里的不同命令隔开:

  1. sed 's/foo/bar/g ; s/chicken/cow/g' myfile.xml > myfile2.xml

不过,许多商用sed版本不支持此功能。

3.2.8 sed的运作

sed读取每个文件,一次读一行,将读取的行放到内存的一个区域--称之为模式空间(pattern space)。

3.2.8.1 打印与否

-n选项修改了sed的默认行为。当提供此选项时,sed将不会在操作完成后打印模式空间的最后内容。反之,若在脚本里使用p,则会明白地将此行显示出来。

  1. sed -n '/<HTML>/p' *.html 仅显示<HTML>这行

3.2.9 匹配特定行

sed默认地会将每一个编辑命令(editing command)应用到每个输入行。它还可以限制一条命令要应用到哪些行,只要在命令前置一个地址(address)即可。因此,sed命令的完整形式就是:

  1. address command

以下为不同种类的地址:
正则表达式
将一模式放置到一条命令之前,可限制命令应用于匹配模式的行。可与s命令搭配使用:

  1. /oldfunc/ s/$/# XXX: migrate to newfunc/ 注释部分源代码

s命令里的空模式指的是“使用前一个正则表达式”:

  1. /Tolstoy/ s//& and Camus/g 提及两位作者

最终行
符号$指“最后一行”。下面的脚本指的是快速打印文件的最后一行:

  1. sed -n '$p' "$1" 引号里为指定显示的数据

对sed而言,“最后一行”指的是输入数据的最后一行。即便是处理多个文件,sed也将它们视为一个长的输入流,且$只应用到最后一个文件的最后一行。

行编号
可以使用绝对的行编号作为地址。

范围
可指定行的范围,仅需将地址以逗号隔开:

  1. sed -n '10,42p' foo.xml 仅打印10-42
  2. sed '/foo/,/bar/ s/baz/quux/g' 仅替换范围内的行

第二个命令为“从含有foo的行开始,再匹配是否有bar的行,再将匹配后的结果中,有baz的全换成quux”。

这种以逗号隔开两个表达式的方式称为范围表达式(range expression)。

否定正则表达式
有时,将命令应用于不匹配于特定模式的每一行,也是很有用的。通过将!加在正则表达式后面就能做到。

  1. /used/ !s /new/used/g 将没有used的每个行里的new改成used

POSIX标准指出:空白(whitespace)跟随再!之后的行为是“未定义的(unspecified)”,并建议需提供完整可移植性的应用软件,不要在!之后放置任何空白字符。

3.2.10 有多少文本会改动

正则表达式匹配可以匹配整个表达式的输入文本最长的,最左边的子字符串。除此之外,匹配的空(null)字符串,则被认为是比完全不匹配的还长。再者,POSIX标准指出:“完全一致的匹配,指的是自最左边开始匹配、针对每一个子模式、由左至右,必须匹配到最长的可能字符串”。(子模式指的是在ERE下圆括号里的部分。为此目的,GNU的程序通常也会在BRE里以\ (...\ )提供此功能)。
sed_1
在文本查找时有可能会匹配到null字符串。而在执行文本替代时,也允许你插入文本:
sed_2

3.2.11 行 v.s. 字符串

大部分简易程序都是处理输入数据的行,像grep与egrep,以及sed大部分的工作都是这样。在这种情况下,不会有内嵌的换行字符出现在将要匹配的数据中,^与$则分别表示行的开头与结尾。

然而,对可应用的正则表达式的程序语言,例如awk、Perl以及Python,所处理的就多半是字符串。若每个字符串表示的就是独立的一行输入,则^与$仍旧可分别表示行的开头与结尾。不过这些程序语言,起始可以让你使用不同的方式来标明每条输入记录的定界符,所以有可能单独输入的“行”(记录)里会有内嵌的换行字符。这种情况下,^与$无法匹配内嵌的换行字符;它们只用来表示字符串的开头与结尾。

3.3 字段处理

字段(field)指的就是记录的组成部分。

3.3.1 文本文件惯例

在文本文件下,一行表示一个记录。各字段都以任意长度的空格(space)或制表(Tab)字符隔开。第二种惯例是使用特定的定界符来分隔字段,例如冒号。两种惯例都有其优缺点。

3.3.2 使用cut选定字段

cut命令是用来剪下文本文件里的数据,文本文件可以是字段类型或是字符类型。后一种数据类型在遇到需要从文件里剪下来特定的列时,特别方便。请注意:一个制表字符在此被视为单个字符。
cut_1
上面的命令可显示系统上每个用户的登录名称及全名。

通过选择其他字段编号,还可以取出每个用户的根目录:
cut_2
通过子都列表做剪下操作有时是很方便的。例如,你只要取出命令ls -l的输出结果中的文件权限字段:
cut_3
不过这种用法比使用字段的风险要大。因为你无法保证行内的每一个字段长度总是一样的。一般来说,我们偏好以字段为基础来提取数据。

3.3.3 使用join连接字段

join命令可以将多个文件结合在一起,每个文件里的每条记录,都共享一个键值(key),键值指的是记录中的主字段。

sales

quotas

每条记录都有两个字段:工人的名字与其相对应的量。
下面的脚本程序merge-sales.sh即为使用join结合两个文件。

merge-sales

首先,使用sed删除注释,然后再排序个别文件。排序后的缓存文件成为join命令的输入数据,最后删除缓存文件。这是执行后的结果:
merge-results

3.3.4 使用awk重新编排字段

awk主要的设计是要在Shell脚本中发挥所长:做一些简易的文本处理,例如取出字段并重新编排这一类。

3.3.4.1 模式与操作

  1. awk 'program' [file ...]

awk读取命令行上所指定的各个文件(若无,则为标准输入),一次读取一条记录(行)。再针对每一行,应用程序所指定的命令。awk程序基本架构为:

  1. pattern {action}
  2. pattern {action}

pattern部分几乎可以是任何表达式,但是在单命令行程序里,它通常是由斜杠括起来的ERE。action为任意的awk语句,但是在单命令行程序里,通常是一个直接明了的print语句。

省略pattern,则会对每一条输入记录执行action;;省略action则等同于{print},将显示整条记录。
大部分单命令行程序为这样的形式:

  1. ... | awk '{print some-stuff} ' | ...

对每条记录来说,awk会测试程序里的每个pattern。若模式值为真(例如某条记录匹配于正则表达式,或是一般表达式计算为真),则awk便执行action内的程序代码。

3.3.4.2 字段

awk读取输入记录(通常是一些行),然后自动将各个记录切分为字段。awk将每条记录内的字段数目,存储到内建变量NF。
awk特别之处就是:也可以设置它为一个完整的ERE,这种情况下,每一个匹配在该ERE的文本都将视为字段分隔字符。
如需字段值,则是搭配$字符。通常$之后会借一个数值常数,也可能是接着一个表达式,不过多半是使用变量名称。

  1. awk '{ print $1 }' 打印第1个字段(未指定pattern)
  2. awk '{ print $2, $5 }' 打印第2与第5个字段(未指定pattern
  3. awk '{ print $1, $NF }' 打印第1个与最后一个字段(未制定pattern
  4. awk 'NF > 0' { print $0 }' 打印非空行(指定pattern与action)
  5. awk 'NF > 0' 同上(未制定action,则默认为打印)

比较特别的字段是编号0:表示整条记录。

3.3.4.3 设置字段分隔字符

在一些简单程序中,你可以使用-F选项修改字段分隔字符。例如,显示/etc/passwd文件里的用户名与全名,你可以:

  1. $ awk -F: '{print $1, $5}' /etc/passwd

-F选项会自动地设置FS变量。
你会发现每一个空格来分隔的。
必须设置OFS变量,改变输出字段分隔字符。方式是在命令行里使用-v选项,这会设置awk的匾蛉。

  1. $ awk -F: -v 'OFS=**' '{ print $1, $5}' /etc/passwd

3.3.4.4 打印行

上面提到简单明了的print语句,如果没有任何参数,则等同于print $0, 极限是整条记录。
在混合文本与数值的情况下,多半会使用awk版本的printf语句。

  1. $ awk -F: '{ printf "User %s is really %s\n", $1, $5 }' /etc/passwd

awk的print语句会自动提供最后的换行字符。如果是printf则需要用户自己提供\n。
注意
在print的参数间用逗号隔开!否则,awk将连接相邻的所有值。

3.3.4.5 起始与清除

BEGIN与END这两个特殊的“模式”,它们提供awk程序起始(startup)与清除(cleanup)操作。
常见于awk程序中,且通常写在个别文件里,而不是在命令行上:
BEGIN { 起始擦欧总程序代码(startup code) }
pattern1 { action1 }
pattern2 { action2 }
END { 清除操作程序代码(cleanup code) }
BEGIN与END的语句块是可选用的。
以简单程序来看, BEGIN可用来设置变量:

  1. $awk 'BEGIN { FS = ":"; OFS = "**" } 使用BEGIN设置变量
  2. > { print $1, $5 }' /etc/passwd 被引用的程序继续到第二行
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注