第一章 强大的编辑工具
字符流编辑器(sed)
sed是一个“非交互式的”面向字符流的编辑器。
Ø sed在一个或多个文件上自动实现编辑操作
Ø 简化对多个文件执行相同编辑处理工作
Ø 编写转换程序
模式匹配的程序设计语言(awk)
awk能够完成的一些功能:
Ø 将文本文件看作由记录和字段组成的文本数据库
Ø 使用变量操作数据库
Ø 使用算术和字符串操作符
Ø 使用普通的程序设计结构
Ø 生成格式化报告
Ø 定义函数
Ø 从脚本中执行UNIX命令
Ø 处理UNIX命令的结果
Ø 更巧妙的处理命令行的参数
Ø 更容易的处理多个输入
第二章 了解基本操作
使用sed
调用sed有两种方法:在命令行上指定编辑指令,或者将他们放到一个文件中并提供这个文件的名字。
在命令行上指定简单的编辑命令
sed –e ‘instruction’ file
只有在命令行上给出多个指令时才需要使用-e选项。
并不是在任何时候都需要将指令用单引号括起来,但应该有这个习惯,使用单引号可以阻止shell解释编辑指令中的特殊字符或空格(shell使用空空格决定提交给程序的独立参数,特殊的shell字符在调用之前被展开)。
有3种方法可以指定命令行上的多重指令:
1. 用分号分隔指令
sed ‘s/ MA/,
2. 在每个指令前放置-e
sed –e ‘s/ MA/,
3. 使用Bourne shell的分行指令功能。在输入单引号后按RETURN键,就会出现多行输入提示符。
这个技术在C shell中不能使用。在C shell中的方法是,在每个指令的结尾使用分号,并且通过反斜杠作为每一行的结束,从而可以输入跨越多行的命令。
脚本文件
执行脚本文件使用-f选项
sed -f scriptfile file
保存输出
只有将sed的输出重定向(>)到另一个文件中,才能捕获文件中的输出。
阻止输入行的自动显示
sed的默认操作是输出每个输入行。-n选项可以阻止自动输出。当指定该选项时,每个生成输出的指令都必须包含打印命令p。
使用awk
awk命令行运行的语法是:
awk ‘instructions’ file
每次从一个或多个文件中读取一行或从标准中读入一行。指令必须包含在单引号内,从而与shell区别开(指令几乎总是包含大括号和/或美元符号,shell将他们解释为特殊符号)。可以用与sed相同的方式输入多重命令行。
用脚本文件调用awk的语法如下:
awk -f script file
-f选项的工作方式与sed中相同。
在通常的情况下,awk将每个输入行解释为一条记录而将那一行上的每个单词(由空格和制表符分隔)解释为一个字段(可以改变这些默认设置)。一个或多个连续的空格或制表符被看作一个定界符。awk允许在模式或过程中引用这些字段。$0代表整个输入行。$1、$2…...表示输入行上的各个字段。应用脚本之前,awk先拆分输入记录。
|
选项 |
描述 |
|
-f |
跟随脚本的文本名 |
|
-F |
改变字段的分隔符 |
|
-v |
跟随 var=value |
同时使用sed和awk
第三章 了解正则表达式语法
元字符(.)可以作为通配符匹配任意单个字符。
元字符(*)用于与他前面的正则表达式的零个或多个出现匹配。星号元字符本身不匹配任何字符,它用于修改它前面的内容。正则表达式 .*匹配任意数目的字符。
元字符汇总
|
特殊字符 |
用途 |
|
. |
匹配除换行符以外的任意单个字符。在awk中,句点也能匹配换行符。 |
|
* |
匹配任意一个(包括零个)在它前面的字符(包括由正则表达式指定的字符) |
|
[…] |
匹配方括号中的字符类中的任意一个。如果方括号中第一个字符为脱字符号(^),则表示否定匹配,即匹配除了换行符和类中列出的那些字符范围的所有字符。在awk中,也匹配换行符。连字符(-)用于表示字符的范围。如果类中的第一个字符为右方括号( ] )则表示她是类成员。所有其它的原字符在被指定为类中的成员时都会失去它本身的含义。 |
|
^ |
如果作为正则表达式的第一个字符,则表示匹配行的开始。在awk中匹配字符串的开始,即使字符串包含嵌入的换行符。 |
|
$ |
如果作为正则表达式的最后一个字符,则表示匹配行的结尾。在awk中匹配字符串的结尾,即使字符串包含嵌入的换行符。 |
|
\{m,n\} |
匹配它前面某个范围内单个字符出现的次数(包括由正则表达式指定的字符)。\{n\}将匹配n次出现,\{n,\}至少匹配n次出现,而且\{m,n\}匹配n和m之间任意次出现。 |
|
\ |
转义随后的特殊字符 |
扩展的元字符(egrep和awk)
|
特殊字符 |
用途 |
|
+ |
匹配前面的正则表达式的一次或多次出现 |
|
? |
匹配前面的正则表达式的零次或一次出现 |
|
| |
指定可以匹配其前面的或后面的正则表达式(替代方案) |
|
() |
对正则表达式分组 |
|
{n,m} |
匹配它前面末各范围内单个字符出现的次数(包括由正则表达式指定的字符)。{n}表示将匹配n次出现,{n,}至少匹配n次出现,{n,m}匹配n和m之间的任意次出现。 |
|
|
|
普遍存在的反斜杠
元字符反斜杠(\)将元字符转化成为普通字符(和将普通字符转化为元字符)。它强制将任意元字符解释为普通文字,以便匹配该字符本身。也可以使用反斜杠将一组普通字符解释为元字符。如:“ \n”结构中n表示从1到9之间的一个数字。
编写正则表达式
编写正则表达式的过程涉及3个步骤:
1. 知道要匹配的内容以及它如何出现在文本中。
2. 编写一个模式来描述要匹配的内容。
3. 测试模式来查看它匹配的内容。
字符类
使用方括号元字符将字符列表括起来,其中每一个字符占据一个位置。文档可以
与在方括号内的任一字符匹配。字符类在处理大小写字母时非常有用。例如:[Ww]hat,指定what的大小写。下表列出方括号中具有特殊含义的字符。
|
字符 |
功能 |
|
\ |
转义任意特殊字符(只用于awk中) |
|
- |
当它不再第一个或最后一个位置时,表示一个范围 |
|
^ |
仅当在第一个位置时表示反转配置 |
字符的范围
连字符(-)用于指定一个字符范围。例如,所有大写英文字母的范围可以指定为[A-Z]
如果闭括号( ] )是作为类中的第一个字符出现(或者是脱字符后的第一个字符),那么他就被解释为类的一个成员。如果连字符在一个类中是第一个或者是最后一个字符,则失去其特殊含义。
排除字符类
通常,字符类包括在那个位置想要匹配的所有字符。在类中作为第一个字符的脱字符(^)将类中的所有字符都排除在匹配之外,除了换行符以外的没有列在方括号中的任意字符都将被匹配。
POSIX字符类补充
POSIX标准对正则表达式字符和操作符的含义进行了形式化。这种标准定义了两类正则表达式:基本正则表达式(BER),grep和sed使用这种正则表达式;扩展的正则表达式,egrep和awk使用这种正则表达式。
POSIX标准提供了附加的字母序列,当匹配和调整(排序)字符串数据时,这些字符序列应该被作为单个单元看待。
POSIX还改变了常用的术语。一直成为“字符类”的东西在POSIX标准中称为“括号表达式”。在括号表达式中,除了字面字符(例如,a、!等)以外,还可以有其它标记。如下:
Ø 字符类:
由 [: 和 :]包围的关键字组成的POSIX字符类。关键字描述了不同的字符类,例如,文字字符,控制字符等等
Ø 整理符号:
整理符号是多字符的序列,表示这些字符应该被看作是一个单元。它由[.和.]包围的字符组成
Ø 等价类:
等价类列出了应该看作是等价的字符集,它由地区化的字符元素(由[=和=]包围)组成
所有的这3种结构都必须出现在括号表达式的方括号中。例如 [[:alpha:]!]匹配任意单个字母字符或感叹号,[[.ch.]]匹配整理元素ch,但不匹配字母c或字母h。在法语地区[[=e=]可以匹配任意e、è或é 。
|
类 |
匹配字符 |
|
[:alnum:] |
可打印的字符(包括空白字符) |
|
[:alpha:] |
字母字符 |
|
[:blank:] |
空格和制表符 |
|
[:cntrl:] |
控制字符 |
|
[:digit:] |
数字字符 |
|
[:graph:] |
可打印的和可见的(非空格)字符 |
|
[:lower:] |
小写字符 |
|
[:print:] |
可打印的字符(包括空白字符) |
|
[:punct:] |
标点符号字符 |
|
[:space:] |
空白字符 |
|
[:upper:] |
大写字符 |
|
[:xdigit:] |
十六进制数字 |
重复出现的字符
星号(*)元字符表示它前面的正则表达式可以出现零次或多次。也就是说,如果它修饰的单个字符,那么该字符可以在那里也可以不在那里,并且如果他在那里,那可能会不止出现一次。
当星号元字符前面有句点元字符时(贪婪模式),表示匹配任意数目的字符。可以用于标识两个固定的字符串之间的字符的跨度。可以匹配任意字符串。
星号用于修饰字符类时,则可以匹配类中的任意数目的字符。例如:
can[ no’]*t
可以匹配can的所有否定形式,但不匹配肯定语句
第四章 编写sed脚本
1. 在脚本中应用命令
sed首先将整个编辑脚本应用于第一个输入行,然后在读取第二个输入行并对其应用整个脚本。因为sed总是处理原始行的最新形式,所以生成的任何编辑工作都会改变后续命令应用的行。sed不会保留最初的行。这就意味着与原始输入行匹配的模式可能不再经过编辑操作之后的行匹配。(这句话没有搞懂什么意思)
例如:
# more test1.dat
the cow,the dog,
the dog is dog
dog not cow
# more test1.scr
s/dog/cow/g
s/cow/horse/g
# sed -f test1.scr test1.dat
the horse,the horse,
the horse is horse
horse not horse
2. 模式空间
sed维护一种模式空间,即一个工作区域或临时缓冲区,当应用编辑命令时将在那里存储单个输入行。
初始时,模式空间包含有单个输入行的备份。脚本中正常的流程是在这一行上执行每个命令直到脚本完。脚本第一个命令对输入行进行匹配,以后将不对最初输入行进行匹配,它匹配模式空间中已被第一个命令进行改变的当前行。结果是,任何sed命令都可以为应用下一个命令改变模式空间中的内容。模式空间的内容是动态的,而且并不总是匹配最初的输入行。
3. 寻址上的全局透视
sed命令应用于每个输入行。sed是隐形全局的。sed处理每一行,除非通过正则表达式指定地址。sed可以指定零个、一个或两个地址。每个地址都是一个描述模式、行号或者行寻址符号的正则表达式。例如:
# more test1.dat
the cow,the dog,
the dog is dog
dog not cow
# sed '/the/s/dog/horse/g' test1.dat
the cow,the horse,
the horse is horse
dog not cow
Ø 如果没有指定地址,那么命令将应用于每一行。
Ø 如果只有一个地址,那么命令应用于与这个地址匹配的任意行。
Ø 如果指定了由逗号分隔的两个地址,那么命令应用于匹配第一个地址的第一行和它后面的行,直到匹配第二个地址的行(包括此行)。
Ø 如果地址后面跟有感叹号(!),那么命令就应用于不匹配该地址的所有行。
例如:1,/^$/d 这个命令删除从第一行开始直到第一个空格行的所有行。
可以把第一个地址看作是启动动作,并把第二个地址看作禁用动作。sed没有办法先行决定第二个地址是否会匹配。一旦匹配了第一个地址,这个动作就将应用于这些行。于是命令应用于“所有”随后的行直到第二个地址被匹配。
4. 分组命令
sed使用大括号({})将一个地址嵌套在另一个地址中,或者在相同的地址上应用多个命令。如果想指定行的范围,然后在这个范围内指定另一个地址,则可以嵌套地址。例如,为了只删除 .TS; .TE块中的空行,使用下面命令:
/^\.TS/,/^\.TE/{
/^$/d
}
左大括号必须在行末,而且右大括号本身必须单独占一行。要确保在大括号之后没有空格。
可以使用大括号将编辑命令括起来以对某个范围的行应用多个命令,如下所示:
/^\.TS/,/^\.TE/{
/^$/d
s/^\.ps 10/ .ps 8/
s/^\.vs 12/ .vs 10/