第18章 过滤器:统计和格式化

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 选项移除标题
相关推荐
DeeplyMind2 小时前
ROCm rocr-libhsakmt性能跟踪与分析系列10-5:跟踪启动、数据采集与停止
linux·驱动开发
jerryinwuhan2 小时前
linux_1219_1
linux
@小博的博客2 小时前
Linux的工具第一篇:vim编辑器的使用详解
linux·编辑器·vim
叮咚侠2 小时前
Ubuntu 24.04.3 LTS如何扩容逻辑卷
linux·数据库·ubuntu
路溪非溪2 小时前
UBUS基本使用总结
linux·网络·arm开发·智能路由器
互联网哪些事情2 小时前
Docker 容器化部署宝塔 Linux 面板
linux·docker·容器·宝塔云服务器
Destiny_where2 小时前
k8s常用指令集合
linux·docker·kubernetes
诸神黄昏EX2 小时前
Android Qualcomm USB 专题系列【总篇:USB HAL架构】
android·linux·网络
DeeplyMind3 小时前
Linux 页表机制详解(x86_64 架构)
linux·驱动开发