18.1 创建行号:nl
nl 过滤器提供一个简单但是有用的服务:它在文本中插入行号。其语法为:
shell
nl [-v start] [-i increment] [-b a] [-n ln|rn|rx] [file...]
其中 stat 是起始号,increment 是增量,而 file 是文件的名称。
nl 程序可以追溯到 Unix 的初期,用来在打印之前向文本中插入行号,例如,如下命令对两个文件进行编号,然后再将输出重定向到 lpr 程序,后者将把数据发送给默认打印机(Unix 中打印文件的 两个基本程序是 lp 和 lpr):
shell
nl measurements1 measurements2 | lpr
默认情况下,nl 按 1、2、3......的规律生成编号,但提供几种选项,来控制编号:
- -v 选项可以改变起始编号;
- -i 选项可以改变增量;
默认情况下,如果数据中有空行,那么 nl 将不对空行编号。为了强制 nl 对所有行编号,可以使用 -b(body numbering,正文编号)选项,后面跟字母 a(all lines,所有行):
shell
nl -b a file
其次,还可以使用 -n(number format,数字格式)选项,后面再跟一个代码来控制数字的格式:
- ln = 左对齐,没有前导 0;
- rn = 右对齐,没有前导 0;
- rz = 右对齐,有前导 0;
下面的命令结合了上面的选项:
shell
nl -v 100 -i 5 -b a -n rz file
18.2 统计行、单词和字符数量:wc
wc(word count,单词统计)程序统计行、单词和字符的数量。其语法为:
shell
wc [-clLw] [file...]
wc 程序非常有用,因为可以在管道线中使用 wc 分析任何程序的文本输出。例如统计 ls 的输出有多少行来计算有多少个文件。
默认情况下,wc 的输出包含三个数字:数据中的行数、单词数和字符数:
- 字符 就是字母、数字、标点符号、空格、制表符或者新行字符;
- 单词 就是一串连续的字符,用空格、制表符或新行字符分隔;
- 行 就是以新行字符结尾的一串字符;
如果不希望显示全部 3个数字,即可以使用选项:
- -l 统计行;
- -w 统计单词;
- -c 统计字符;
对于 Linux 来说,还有另外一个选项:-L,用于显示输入中的最长行的长度。
shell
ls /etc | wc -l # 统计 /etc 中的文件的数量
who | wc -l # 查看已经登录到系统的用户标识的数量
echo "There are `who | wc -l` userids logged in right now."
18.3 Unix 使用制表符的方式
<Tab> 键继承自打字机上所使用的制表符。
单词 tab 是 tabulate(制表)的缩写,意味着将信息组织成表格。老式打字机上的 键被设计用来帮助按列排列信息,并在段落的开头缩进文本。
制表位(tab stop)是设置的每一行中的位置。Unix 被设计为无论何时,当终端遇到制表符时,它都像打字机一样将光标移动到当前行的下一个制表位。即 Unix 终端铜鼓将光标移动到下一个制表位来显示制表符。
默认情况下,Unix 假定每隔8个字符(从位置1开始)有一个制表位。因此,默认 Unix 的制表位是 1、9、17、25、33 等。
当希望缩进文本或者按列对齐数据时,既可以使用空格也可以使用制表符,但最好使用空格。
18.4 可视化制表符和空格
制表符和空格都是不可见的,为了能够看到不可见的字符,有几种方法:
VI 编辑器使用如下方法:
使用命令 :set list
空格依旧不可见,但是制表符都将显示为 ^I,即 ASCII码中表示制表符的控制字符.
为了关闭该选项,可以使用 :set nolist
Nano 或 Pico 编辑器(Nano 是 GNU 版本的 Pico)
Open Office 这种办公应用程序,可以打开 View 菜单选择 Nonprinting Characters。
18.5 将制表符转为空格:expand
语法为:
shell
expand [-i] [-t size | -t list] [file...]
其中 size 是固定宽度制表符的大小,list 是制表位列表,而 file 是文件的名称。
expand 程序将输入文件中的所有制表符改变成空格,并且同时维持与原始文本相同的对齐方式。
shell
expand animals > animals-expanded
默认情况下,expand 使用的是 Unix 惯例,每8个位置有一个制表位。使用 -t(tab stop,制表位)选项可以改变该设置。-t 现象有两种使用方式,第一种如果所有制表位都是相同间距,则在 -t 之后跟一个数字,例如:
shell
expand -t 4 data > data-new
# 将 Unix 的默认8个字符一个制表位改为4个,并以此来继续替换
而 -t 8 则等价于 Unix 的默认制表位设置,即每隔8个字符设置一个制表位;-t 4 将每隔 4个位置创建一个制表位。
-t 选项还有另一种使用方式:如果希望制表位位于特定的位置上,则可以指定一串用逗号分开的多个数字,编号从0开始,例如:
shell
expand -t 7,15,21,56 data > data-new
# 将制表位设置在位置8、16、22 和 57 上,然后用 expand 替换为空格
-i 选项表示只转换开头的制表符,其他所有的制表符保持不变:
shell
expand -i -t 4 data > data-new
expand 程序对含有制表符的文本文件的预处理非常有用,特别是当其他程序期望在这些文件发送给它们之前,文件按列准确对齐时:
shell
expand -t 4 statistics | cut -c 1-15 | sort
18.6 将空格转换成制表符:unexpand
unexpand 程序的语法为:
shell
unexpand [-a] [-t size | -t list] [file...]
其中 size 是固定宽度制表符的大小,list 是制表位列表,而 file 是文件的名称。
unexpand 是 expand 的逆过程,其选项也类似,但是 expand 和unexpand 之间最重要的区别就是默认情况下,unexpand 程序只替换行开头的空格。
如果要替换所有空格,则可以使用 -a(all,全部)选项。
shell
unexpand -t 4 rough-notes > mickey
18.7 格式化行:fold
fold 程序执行一项简单的任务:将长行分隔成短行。其语法为:
shell
fold [-s] [-w width] [file...]
其中 width 是新行的最大宽度(默认为 80),file 是文件的名称。
当 fold 程序分隔行时,它所作的就是在合适位置上插入一个回车符,使一行变成两行。
shell
fold -w 40 long-lines > short-lines
默认情况下,fold 会把单词给分隔,因此需要使用 -s 选项,告诉 fold 不分隔单词:
shell
fold -s -w 40 speech > speech-formatted
# 对于一些程序来说,可能发现每次使用这个程序时都使用相同的选项,因此可以创建包含选项的别名
alias fold="fold -a -w 40"
\fold -w 60 long-text > short-text # 临时挂起别名
18.8 80字符行
许多 Unix 程序仍然使用80字符每行作为默认设置。其原因是因为 IBM 的计算机开发出来时,使用了能存储80个字符的穿孔卡片,结果,程序和数据都存储为每行80个字符,而且在极短时间内成为了事实上的标准。
后来即使开始使用终端,但是80字符标准被保留了下来。
18.9 格式化段落:fmt
fmt 程序格式化段落。fmt 的目标就是将段落中的各行连接在一起,从而是段落尽可能短小和紧凑,而且还不改变内容和空白符。换句话说,就是 fmt 就文本看上去更漂亮。其语法为:
shell
fmt [-su] [-w width] [file...]
当 fmt 读取文本时,它假定段落由空行分隔。因此,一个段落就是一个或多个连续的文本行,不包含空行。
shell
fmt -w 50 secret-raw > secret-formatted
-u(uniform spacing,统一间距)选项告诉 fmt 减少空格,从而使单词之间最多只有一个空格,而句子末尾最多只有两个空格,这一样式称为法国式间距(French spacing);
-s(split only,仅拆分),该选项告诉 fmt 拆分长行,但是不连接短行。当处理希望保存原格式的文件时可以使用这个选项。
18.10 打印的旧时代
pr 程序是 Unix 初期创建的一个程序,即 20世纪70年代。设计 pr 是用来在共享环境中打印准备文件的,但是 pr 程序除了打印基本功能外,在格式化文本方面也有自己的用途。
pr 程序将文本格式化成页;其次,pr 确保每页都有自己的标题、边缘和页号。
18.11 按页格式化文本:pr
pr 的主要功能是按页格式化文本,以使其适合于打印。其基本语法如下:
shell
pr [-dt] [+beg[:end]] [-h text] [-l n] [-o margin] [-W width] [file...]
其中 beg 是需要格式化的第一页,end 是需要格式化的最后一页;text 是标题中间的文本;n 是每页的行数;margin 是左边缘的大小;width 是输出的宽度;file 是文件的名称。
通常将 pr 作为管道线的一部分,以便在讲文本发送给打印机之前对文本呢进行格式化:
shell
calculate | pr | lpr # Unix 中文件打印的两个基本程序是 lp 和 lpr
默认情况下,pr 通过在顶端插入一个标题、左边插入一个边缘、底部插入一个页尾来格式化页面。标题和页尾各占用5行,并假定一页有66行,那么剩下56行用于单倍行距的文本。
shell
fmt essay | pr | less
fold -s essay | pr | less
pr 程序常用的选项如下:
- -d 选项告诉 pr 使用双倍行距文本;
- -l 选项改变每页的总行数;
- -t 选项可以用于消除标题;
- -o(offset,偏移)选项后面跟额外的边缘的空格数量,插入到左边缘;
- -h 选项指定标题中间部分的文本;
- +begin[:end] 选项指定格式化哪些页面;
- -W 选项改变输出的宽度,默认是72个字符;
shell
fold -s -w 45 essay | pr -d -o 5 -W 50 | lpr
将文本发送给 pr 之前使用 fold 或者 fmt 对文本进行预处理时,最好时明确指定希望的准确行宽,因为这3个程序使用不同的默认值:
- fold:80字符
- fmt:75字符
- pr:72字符
18.12 按列格式化文本:pr
当使用 pr 创建数据列时,pr 程序的语法为:
shell
pr [-mt] [-columns] [-l lines] [-W width] [file...]
其中 column 是输出列的数量,lines 是每页的行数,width 是输出的宽度,file 是文件的名称。
pr 默认使用制表符,而不是空格来对齐各列。将文本分列时,pr 会盲目地截断太长的行,因此,如果文本呢所包含行的长度大于列宽,那么在将文本发送给 pr 之前必须使用 fold -s 或者 fmt 分割行。
shell
fmt -w 25 article | pr -2 -l 48 > article-columns
# 将3个文件格式化成3个单独的列
pr -m file1 file2 file3
# 注意分隔成3列后,每列最大的宽度默认情况下是23个字符,因此需要如下格式化:
fmt -w 23 n1 > f1
fmt -w 23 n2 > f2
fmt -w 23 n3 > f3
pr -mt f1 f2 f3 > formatted-articles # -t 选项移除标题