文本处理
摘要:类 Unix 的操作系统都严重依赖于几种数据存储类型的文本文件。本章将看一些被用来“切割”文本的程序。
文本处理
这一章会重新拜访一些老朋友,并且会给我们介绍一些新朋友:
- cat - 连接文件并且打印到标准输出
- sort - 给文本行排序
- uniq - 报告或者省略重复行
- cut - 从每行中删除文本区域
- paste - 合并文件文本行
- join - 基于某个共享字段来联合两个文件的文本行
- comm - 逐行比较两个有序的文件
- diff - 逐行比较文件
- patch - 给原始文件打补丁
- tr - 翻译或删除字符
- sed - 用于筛选和转换文本的流编辑器
- aspell - 交互式拼写检查器
文本应用程序
前边我们了解了vim和nano两个文本编辑器。文本还能来做什么呢?
文档
纯文本格式写文档,然后用一种标记语言(如Markdown)来描述文档的格式。
网页
网页是文本文档,它们使用 HTML(超文本标记语言)或者是 XML (可扩展的标记语言)作为标记语言来描述文档的可视格式。
电子邮件
从本质上来说,email 是一个基于文本的媒介。
打印输出
在类 Unix 的系统中,输出会以纯文本格式发送到打印机,或者如果页面包含图形,其会被转换成一种文本格式的页面描述语言,以 PostScript 著称,然后再被发送给一款能产生图形点阵的程序,最后被打印出来。
程序源码
源代码,程序员实际编写的一部分程序,总是文本格式。
回顾一些老朋友
回到第 7 章(重定向),我们已经知道一些命令除了接受命令行参数之外,还能够接受标准输入。现在我们将仔细地看一下它们是怎样被用来执行文本处理的。
cat
cat的许多选项用来帮助更好的可视化文本内容。如-A 选项,其用来在文本中显示非打印字符。
xuxg@xuxg-ubuntu:~$ cat > foo.txt
The quick brown fox jumped over the lazy dog.
xuxg@xuxg-ubuntu:~$ cat -A foo.txt
^IThe quick brown fox jumped over the lazy dog. $
在输出结果中我们看到,这个 tab 字符在我们的文本中由 ˆI 字符来表示。我们也看到一个 $ 字符出现在文本行真正的结尾处,表明我们的文本包含末尾的空格。
Unix 和 DOS 在文本文件中定义每行结束的方式不相同。Unix 通过一个换行符(ASCII 10)来结束一行,然而 MS-DOS 和它的衍生品使用回车(ASCII 13)和换行字符序列来终止每个文本行。
cat 程序也包含用来修改文本的选项。最著名的两个选项是-n,其给文本行添加行号和-s,禁止输出多个空白行。
xuxg@xuxg-ubuntu:~$ cat > foo.txt
The quick brown fox
jumped over the lazy dog.
xuxg@xuxg-ubuntu:~$ cat -ns foo.txt
1 The quick brown fox
2
3 jumped over the lazy dog.
sort
sort 程序对标准输入的内容,或命令行中指定的一个或多个文件进行排序,然后把排序结果发送到标准输出。
sort 程序有几个有趣的选项。这里只是一部分列表:
选项 | 长选项 | 描述 |
---|---|---|
-b | –ignore-leading-blanks | 默认情况下,对整行进行排序,从每行的第一个字符开始。这个选项导致 sort 程序忽略每行开头的空格,从第一个非空白字符开始排序。 |
-f | –ignore-case | 让排序不区分大小写。 |
-n | –numeric-sort | 基于字符串的数值来排序。使用此选项允许根据数字值执行排序,而不是字母值。 |
-r | –reverse | 按相反顺序排序。结果按照降序排列,而不是升序。 |
-k | –key=field1[,field2] | 对从 field1 到 field2 之间的字符排序,而不是整个文本行。看下面的讨论。 |
-m | –merge | 把每个参数看作是一个预先排好序的文件。把多个文件合并成一个排好序的文件,而没有执行额外的排序。 |
o | –output=file | 把排好序的输出结果发送到文件,而不是标准输出。 |
-t | –field-separator=char | 定义域分隔字符。默认情况下,域由空格或制表符分隔。 |
uniq
当给定一个排好序的文件(包括标准输出),uniq 会删除任意重复行,并且把结果发送到标准输出。它常常和 sort 程序一块使用,来清理重复的输出。
uniq 程序有几个选项。这里是一些常用选项:
选项 | 说明 |
---|---|
-c | 输出所有的重复行,并且每行开头显示重复的次数。 |
-d | 只输出重复行,而不是特有的文本行。 |
-f n | 忽略每行开头的 n 个字段,字段之间由空格分隔,正如 sort程序中的空格分隔符;然而,不同于 sort 程序,uniq 没有选项来设置备用的字段分隔符。 |
-i | 在比较文本行的时候忽略大小写。 |
-s n | 跳过(忽略)每行开头的 n 个字符。 |
-u | 只输出独有的文本行。这是默认的。 |
切片和切块
下面我们将要讨论的三个程序用来从文件中获得文本列,并且以有用的方式重组它们。
cut
cut 程序被用来从文本行中抽取文本,并把其输出到标准输出。它能够接受多个文件参数或者标准输入。
从文本行中指定要抽取的文本有些麻烦,使用以下选项:
选项 | 说明 |
---|---|
-c char_list | 从文本行中抽取由 char_list 定义的文本。这个列表可能由一个或多个逗号分隔开的数值区间组成。 |
-f field_list | 从文本行中抽取一个或多个由 field_list 定义的字段。这个列表可能包括一个或多个字段,或由逗号分隔开的字段区间。 |
-d delim_char | 当指定-f 选项之后,使用 delim_char 做为字段分隔符。默认情况下,字段之间必须由单个 tab 字符分隔开。 |
–complement | 抽取整个文本行,除了那些由-c 和/或-f 选项指定的文本。 |
paste
paste 命令的功能正好与 cut 相反。它会添加一个或多个文本列到文件中。paste 接受多个文件参数和/或标准输入。
join
join 命令类似于 paste,它会往文件中添加列,但是它使用了独特的方法来完成。一个 join 操作通常与关系型数据库有关联,在关系型数据库中来自多个享有共同关键域的表格的数据结合起来,得到一个期望的结果。这个 join 程序执行相同的操作。它把来自于多个基于共享关键域的文件的数据结合起来。
比较文本
例如,需要拿现有的配置文件与先前的版本做比较,来诊断一个系统错误。
comm
comm 程序会比较两个文本文件,并且会显示每个文件特有的文本行和共有的文把行。
diff
diff 程序被用来监测文件之间的差异。它支持许多输出格式,并且一次能处理许多文本文件。
patch
patch 程序被用来把更改应用到文本文件中。它接受从 diff 程序的输出,并且通常被用来把较老的文件版本转变为较新的文件版本。
运行时编辑
我们对于文本编辑器的经验是它们主要是交互式的,意思是我们手动移动光标,然后输入我们的修改。然而,也有非交互式的方法来编辑文本。有可能,例如,通过单个命令把一系列修改应用到多个文件中。
tr
tr 程序被用来更改字符。可以把它看作是一种基于字符的查找和替换操作。
sed
sed 是 stream editor(流编辑器)的简称。它对文本流,即一系列指定的文件或标准输入进行编辑。
sed 是一款非常强大的程序,它能够针对文本流完成相当复杂的编辑任务。
aspell
aspell,一款交互式的拼写检查器。
除非由命令行选项 --dont-backup 告诉 aspell,否则通过追加扩展名.bak 到文件名中, aspell会创建一个包含原始文本的备份文件。
总结归纳
在这一章中,我们已经查看了一些操作文本的命令行工具。在下一章中,我们会再看几个命令行工具。
有一些更有趣的文本操作命令值得。在它们之间有:split(把文件分割成碎片),csplit(基于上下文把文件分割成碎片),和 sdiff(并排合并文件差异)。