第二十一章 格式化输出
第二十一章 格式化输出
本章仍然是文本相关的工具,重点放在格式文本输出而非更改文本本身的程序上。
命令如下:
- nl:对行进行编号。
- fold:在制定长度处折行。
- fmt:一个简单的文本格式化工具。
- pr:格式化要输出的文本。
- printf:格式化并输出数据。
- groff:文档格式化系统。
简单的格式化工具
这些工具大多是单一用途的程序,其工作方式并不复杂,但是可以用于小型任务或作为管道和脚本的一部分。
nl-对行进行编号
nl命令任务非常简单,对行进行编号,其格式如下:
nl filename #显示文件名为filename的文件的内容,并显示其行号
nl可以接受多个文件参数或标准输入。但是nl具有很多选项,支持原始形式的标记,能够实现更为复杂的编号。
nl支持一个叫作“逻辑页”(logical pages)的特性,这使其在进行编号时能够重置数值序列。逻辑页被划分为页眉、正文及页脚。文本流中的各个部分由文本中所加入的一些标记来指示。
nl标记
标记 | 含义 |
---|---|
\:\:\: | 逻辑页页眉的开始 |
\:\: | 逻辑页正文的开始 |
\: | 逻辑页页脚的开始 |
所示的每个标记都必须出现在单独一行中。处理完标记后,nl会将其从文件流删除。
常用的nl选项
选项 | 含义 |
---|---|
-b sytle | 将正文编号设置为style,其中的style可以是下列取值之一: a表示编号所有行;t表示仅编号非空行,这是默认项;n表示不编号;pregexp表示仅编号BRE regexp的行 |
-f style | 将页脚设置为style。默认值为n(无) |
-h style | 将页眉编号设置为style。默认值为n(无) |
-i number | 将页面编号增量设置为number,默认值为1 |
-n format | 将页面编号格式设置为format,其中的format可以是下列取值之一:ln表示左对齐,不进行0填充(without leading zeros);rn表示右对齐,不进行0填充,这是默认值;rz表示右对齐,进行0填充 |
-p | 不在每个逻辑页开头处重叠页面编号 |
-s string | 在每行行号之后添加string作为分隔符。默认值是单个制表符 |
-v number | 将每个逻辑页中第一行的编号设置为number。默认值1 |
-w width | 将行号字段的宽度设置为width。默认值是6 |
例如使用nl查看foo.txt文件:
foo.txt文件内容如下:
aaa
bbb
ccc
查看命令如下:
nl foo.txt
输出结果如下:
1 aaa
2 bbb
3 ccc
fold-在指定长度处折行
折行是将文本行在制定宽度处断开的过程。fold可以接受一个或多个文件参数,也可以接受标准输入。
例如:向fold发送一个简单的文本流
echo "The quick brown fox jumped over the lazy dog." | fold -w 12
命令输出结果如下:
The quick br
own fox jump
ed over the
lazy dog.
echo 命令输出结果的文本被按照-w选项指定的值拆成了多个片段,在本例中,将行宽制定为12个字符。若未指定行宽,则默认为80个字符。
fmt-一个简单的文本格式化工具
fmt命令也可以将文本折行,除此之外,该命令可以接受文件参数或标准输入,对文本流执行段落格式化操作。
fmt常用格式如下:
fmt [options] filename #将文件名为filename的文件的内容格式化输出到标准输出command | fmt [options] #将command命令的输出结果通过管道交给fmt进行格式化输出。
例如:
fmt选项
选项 | 描述 |
---|---|
-c | 在冠边距(crown margin)模式下操作。该模式保留段落前两行缩进、后续第二行的缩进 |
-p string | 仅格式化已string开头的行。经过格式化之后,string被作为重新格式化后的各行的开头。该选项可用于格式化源代码注释中的文本。 |
-s | 纯分隔(split only)模式。在此模式中,仅分隔行以适应指定列宽,不会连接短行进行填充。在格式化不适合连接的文本时,该选项就能派上用场 |
-u | 均匀间隔(uniform spacing)。对文本应用传统的“打字机样式”(typewriter style)格式。 |
-w width | 格式化文本以适应width个字符的列宽,默认值是75个字符。注意,为了实现平衡(line balancing),fmt实际格式化的行长度会比指定的列宽稍微小一点 |
例如将fmt的info页以50字符列宽显示:
命令如下:
info fmt | fmt -w 50
输出结果如下图:
pr-格式化要输出的文本
pr命令用于对文本进行分页。在输出文本时,通常会用几行空白分隔符输出页面,以便为各项提供上边距和下边距。
例如将distros.txt文件格式化为一系列小号页面:
pr -l 15 -w 65 distros.txt
输出结果如下图:
本例中,制定了-l选项(页面长度)和-w选项(页面宽度),将页面定义为15行、宽65列。
printf-格式化并输出数据
printf命令不适用于管道(不接受标准输入),多用于脚本。
printf(打印格式,print formatted的缩写)是bash的内建命令。
用法如下:
printf "format" arguments
该命令指定一个包含格式描述的字符串,这个字符串会被应用于参数列表。格式化后的结果输出至标准输出。
例如:
printf "I formatted the string: %s\n" foo
输出结果如下图:
格式化字符串可以包含普通文本(如I formatted the string:),转义序列(如\n)以及称为“转换说明”(conversion specifications)的以%开头的序列。
常用的printf数据类型说明符
说明符 | 描述 |
---|---|
d | 将数字格式化为有符号十进制整数 |
f | 格式化并输出浮点数 |
o | 将整数格式化为八进制数 |
s | 格式化字符串 |
x | 将整数格式化为十六进制数,根据需要使用小写字母a~f |
X | 和x功能一样,只不过使用的是大写字母A~F |
% | 输出普通的%(指定%%) |
使用字符串380演示各种说明效果:
说明符还可以添加一些可选组件以调整输出。一个完整的转换说明包括:
%[flags][width][.precision]conversion_specification
printf转换说明的组件
组件 | 描述 |
---|---|
flags | 共有如下5种不同的标志。#: 使用替代格式输出。替代格式取决于数据类型。对于o(八进制)转换,输出结果加上前缀0.对于x和X(十六进制)转换,输出结果分别加上前缀0x和0X;0(数字0):使用0填充输出结果。这意味着会在字段前添加0,例如000380;-(连字符):左对齐输出。默认情况下,printf右对齐输出;‘’(空格符):为正数生成一个前导空格符;+(加号):正数符号。默认情况下,printf只输出负数的符号 |
width | 一个指定字段最小宽度的数字 |
.precision | 对于浮点数,指定了小数点后输出的精度位数。对于字符串转换,指定了输出字符个数 |
printf转换说明示例
参数 | 格式 | 结果 | 说明 |
---|---|---|---|
380 | “%d” | 380 | 简单的整数格式化 |
380 | “%#x” | 0x17c | 使用“替代格式”标志将整数格式化为十六进制数 |
380 | “%05.5f” | 380.00000 | 将数字格式化为精确到小数点后5位的浮点数,位数不足用0填充。由于指定的字段最小宽度(5)少于格式化后实际宽度,因此此处并未进行填充 |
380 | “%010.5f” | 将字段最小宽度增至10,现在就能看到填充效果了 | |
380 | “%+d” | +380 | +标志表示为正数 |
380 | “%-d” | 380 | -标志表示左对齐 |
abcdefghijk | “%5s” | abcedfghijk | 以字段最小宽度格式化字符串 |
abcdefghijk | “%.5s” | abcde | |
对字符串设置精度,导致其被截断 |
文档格式化
文档格式化领域内主要有两大派系:一派源自最初的roff程序,其中包括nroff和troff;另一派则基于TEX排版系统。
roff程序用于格式化要输出到使用等宽字体设备上的文档,例如字符终端和打字机式打印机。它支持几乎所有与计算机相连的打印设备。roff派系还包含了一些用于处理文档部分内容的程序,其中包括eqn(针对数学方程式)和tbl(针对表格)
groff
groff是包含troff的GNU实现在内的一组程序,另外还包括用于仿真nroff和roff派系其他功能的脚本。
如今多数文档都是用文字处理器生成的,文字处理器只用一步就能完成文档的编写和布局。在图形化文字处理器问世之前,生成文档通常包括两个步骤:使用文本编辑器编写内容,使用troff这类处理工具进行格式化。格式化工具的命令都已经通过标记语言嵌入所编写的文本中。
groff因为其标记语言的很多元素处理都是一些相当晦涩的排版细节。但其广泛应用的是宏软件包(macro package)。这些宏软件包将多个低阶命令汇聚成少量的高阶命令集,从而大大简化了groff的使用。