格式化输出

前言

  1. 本章继续讨论与文本相关的工具,重点将一些用于格式文本输出而非改变文本自身内容的命令。
  2. 这些命令通常用于文本的打印,而打印这一主题将在下一章介绍。
  3. 本章将要讨论的命令如下所示:
  • nl: 对行进行标号
  • fold: 设定文本行长度
  • fmt: 简单的文本格式化工具
  • pr: 格式化打印文本
  • printf: 格式化并打印数据

简单的格式化工具

基本介绍

  1. 首先让我们看一些简单的格式化工具,他们多数都是单目的程序,且一般执行一些不复杂的操作,他们一般用于一些小的任务,并作为管道传输和脚本的一部分。

nl - 对行进行标号

  1. nl 基本介绍
  • nl 命令是一个非常神秘的工具,用于完成一个非常简单的任务;对行进行编号。就其最简单用法,与 cat -n 很相似。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [me@linuxbox ~]$ nl distros.txt | head
    1 SUSE 10.2 12/07/2006
    2 Fedora 10.0 11/25/2008
    3 SUSE 11.0 06/19/2008
    4 Ubuntu 8.04 04/24/2008
    5 Fedora 8.00 11/08/2007
    6 SUSE 10.3 10/04/2007
    7 Ubuntu 6.10 10/26/2006
    8 Fedora 7.00 05/31/2007
    9 Ubuntu 7.10 10/18/2007
    10 Ubuntu 7.04 04/19/2007
  • 和 cat 命令一样,nl 既支持多个文件名作为命令行参数,也支持标准输入,然而,nl 可以进行多种复杂的编号,因为它有许多参数选项,且支持原始形式的标记。
  • nl 进行标号时支持一个叫做逻辑页的概念,所以它可以重置数值序列。
  • 通过合理运用参数选项,nl 可以设置起始编码为特定的值,并在有限的范围内设置其格式,逻辑页可以进一步分解为逻辑页标题、正文和页脚。
  • 在每一个部分中,行号都可以重置并/或分配不同的风格。
  • 如果 nl 的输入参数是多个文件,那么 nl 会把它们当做一个文本流整体。
  • 文本流中的每一个部分都由一些看起来非常奇怪的标记来区别。
  1. nl 标记
标记 含义
\:\:\: 逻辑页页眉开头
\:\: 逻辑页正文开头
\: 逻辑页页脚开头
  1. 常用的 nl 选项
选项 含义
-b style 按照 style 对正文进行编号,这里的 style 是下面类型中的一个:a 对每行编号; t 仅仅对非空白行编号,此选项是默认的; n 不对任何行进行编号; pregexp 只对与基本正则表达式匹配的行进行编号
-f style 以 style 的格式对页脚进行编号。默认选项是 n (无)
-h style 以 style 的格式对标题进行编号。默认选项是 n (无)
-i number 设置页编号的步进值为 number。默认值为 1 。
-n format 设置编号格式为 format,此处的 format 可以是如下表示中的一种:ln 左对齐,无缩进;rn 右对齐, 无缩进,这是默认选项;rz 右对齐,有缩进
-p 在每个逻辑页的开始不再进行页编码重置
-s string 在每行行号后面增加 string 作为分隔符。默认的情况下是一个简单的 tab 制表符。
-w width 设置行号字段的宽度为 width 。默认值是 6 。
  1. nl 补充说明
  • 不得不承认,用户可能并不会那么频繁地进行行编号,但是,用户可以利用 nl 结合其他工具进行更复杂的任务。

fold - 将文本的行长度设定为指定长度

  1. fold 是一个将文本行以指定长度分解的操作。与命令行类似,fold 支持一个或多个文本文件或是标准输入作为输入参数。向 fold 输入一个简单的文本流,便可了解其工作方式。
    1
    2
    3
    4
    5
    [me@linuxbox ~]$ echo "The quick brown fox jumped over the lazy dog." | fold -w 12
    The quick br
    own fox jump
    ed over the
    lazy dog.
  2. 这样,我们便能明白 fold 到底完成了什么操作。 echo 命令输出的文本被指定了 -w 选项的 fold 分解成了片段。
  3. 本例中,指定了行的宽度为 12 个字符。如果没有指定行宽,则默认是 80 个字符宽。
  4. 请注意,fold 在断行时并不会考虑单词边界。而增加 -s 选项,可使 fold 到达 width 字符数前的最后一个有效空格将原文本行断开,示例如下:
    1
    2
    3
    4
    5
    6
    [me@linuxbox ~]$ echo "The quick brown fox jumped over the lazy dog." | fold -w 12 -s
    The quick
    brown fox
    jumped over
    the lazy
    dog.

fmt - 简单的文本格式化工具

  1. fmt 基本介绍
  • fmt 命令同样会折叠文本,另外还包括更多的其他功能。它既可以处理文件也可以处理标准输入,并对文本流进行段落格式化。
  • 就其基本功能而言,它可以在保留空白行和缩进的同时对文本进行填充和连接。
  • 作为演示的文本内容,不如从 fmt 帮助手册中复制一些内容吧。
    1
    2
    3
    4
    5
    6
    7
    8
    The fmt utility is a simple text formatter which reads the concatenation of input files (or standard input if none are given) and produces
    on standard output a version of its input with lines as close to the goal length as possible without exceeding the maximum. The goal
    length defaults to 65 and the maximum to 10 more than the goal length. Alternatively, a single width parameter can be specified either by
    prepending a hyphen to it or by using -w. For example, ``fmt -w 72'', ``fmt -72'', and ``fmt 72 72'' all produce identical output. The
    spacing at the beginning of the input lines is preserved in the output, as are blank lines and interword spacing. Lines are joined or
    split only at white space; that is, words are never joined or hyphenated.

    The options are as follows:
  • 将这段文字复制到文本编辑器中,并将其存为 fmt-info.txt 文本文件。
  • 现在,假定我们需要重新格式化该文本,以满足每行 50 个字符宽的规则。那么我们可以输入 fmt 结合 -w 选项完成这样的格式化。
    1
    2
    3
    4
    5
    6
    [me@linuxbox ~]$ fmt -w 50 fmt-info.txt | head
    The fmt utility is a simple text formatter which reads the concatenation of input files (or standard input if none are given) and produces
    on standard output a version of its input with lines as close to the goal length as possible without exceeding the maximum.

    The goal
    length defaults to 65 and the maximum to 10 more than the goal length. Alternatively, a single width parameter can
  • 这个输出结果还真奇怪。也许,实际上我们应该认真地阅读一遍下面的文字,因为它解释了事情发生的原委。
  • 默认情况下,空白行、单词之间的空格和缩进都保留在输出结果中;不同缩进量的连续输入行并不进行拼接,制表符会在输入中扩展并直接输出。
  • 所以,fmt 保留了第一行的缩进。幸运的是,fmt 提供了一个参数选项以修正这一问题。
    1
    2
    3
    4
    5
    6
    7
    [me@linuxbox ~]$ fmt -cw 50 fmt-info.txt | head
    The fmt utility is a simple text formatter which reads the concatenation of input files (or standard input if none are given) and produces
    on standard output a version of its input with lines as close to the goal length as possible without exceeding the maximum. The goal
    length defaults to 65 and the maximum to 10 more than the goal length. Alternatively, a single width parameter can be specified either by
    prepending a hyphen to it or by using -w. For example, ``fmt -w 72'', ``fmt -72'', and ``fmt 72 72'' all produce identical output. The
    spacing at the beginning of the input lines is preserved in the output, as are blank lines and interword spacing. Lines are joined or
    split only at white space; that is, words are never joined or hyphenated.
  • 由此可见,通过增加 -c 选项,我们便得到了理想的输出结果。
  1. fmt 有一些有趣的选项
选项 功能描述
-c 在冠边缘模式下运行,此模式保留段落前两行的缩进,随后的行都与第二行的缩进对齐
-p string 只格式化以前缀字符串 string 开头的行。格式化后,string 的内容仍然会作为每一个格式化的前缀,该选项可以用于格式化内容是源代码的文本,例如,任何以 # 号作为生命开头的编程语言或是配置文件都可以通过指定 -p、# 选项进行格式化,指定该选项后可以保证只格式化声明中的内容。
-s 仅截断行模式。在此模式下,将会只根据指定的列宽截断行,而断行并不会与其他行结合,此模式适用于格式化文本单不需要行拼接的场合。
-u 字符间隔的统一,采取传统的打字机风格模式格式化文本,这意味着字符之间间隔一个空格字符,句子之间间隔两个空格字符。该模式对于删除齐行非常有用,所谓齐行就是指文本行被强迫与左右边缘对齐
-w width 格式化文本使每行不超过 width 个字符,默认值是 75 。请注意, fmt 格式化时往往由于要保持的行平衡而使得行实际宽度比指定高度略小
  1. fmt 补充说明
  • -p 选项尤为有趣,通过它,我们可以选择性地格式化文件内容,前提是要格式化的文本行都以相同的字符序列开头。
  • 许多编程语言都是用 hash (#) 作为注释的开始,因此可以用此选项只格式化注释文本。
  • 下面创建一个有注释的类似于程序的文本文件。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [me@linuxbox ~]$ cat > fmt-code.txt
    # This file contains code with comments

    # This line is a comment.
    # Followed by another comment line.
    # And another.

    This on the other hand, is a line of code.
    And another line of code.
    ANd another.
  • 我们的示例文本包含了以 # (# 后紧跟一个空格)字符串开头的注释以及代码行 (虽然并不是真正意义上的代码) 。现在,我们使用 fmt 格式化该注释内容而不改动代码。
    1
    2
    3
    4
    5
    6
    7
    8
    # This file contains code with comments

    # This line is a comment.Followed by another
    # comment line.And another.

    This on the other hand, is a line of code.
    And another line of code.
    ANd another.
  • 请注意,毗邻的注释行已经拼接起来,但是保留了空白行以及不是以指定前缀开头的文本行。

pr - 格式化打印文本

  1. Pr 命令用于给出文本标页码。
  2. 打印文本时,通常希望将输出内容分成几页,并且每页的顶部和底部都留出几行空白,这些空白可以用于插入页眉和页脚。
  3. 示例如下,该命令行将 distros.txt 文件格式化为一系列非常短的页 (只显示了前两页) 。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    [me@linuxbox ~]$ pr -l 15 -w 65 distros.txt



    1 12 11:09 2021 distros.txt Page 1


    SUSE 10.2 12/07/2006
    Fedora 10.0 11/25/2008
    SUSE 11.0 06/19/2008
    Ubuntu 8.04 04/24/2008
    Fedora 8.00 11/08/2007







    1 12 11:09 2021 distros.txt Page 2


    SUSE 10.3 10/04/2007
    Ubuntu 6.10 10/26/2006
    Fedora 7.00 05/31/2007
    Ubuntu 7.10 10/18/2007
    Ubuntu 7.04 04/19/2007
  4. 上例中,结合了 -l 选项 (页长) 以及 -w 选项 (页宽) 定义了一页内容包含 15 行,每行包含 65 个字符。
  5. pr 对 distros.txt 文件的内容进行分页,页与页之间则用几行空白行隔开,并且创建了一个包含文件修改时间、文件名以及页码的默认页眉。

printf - 格式化并打印数据

  1. printf 基本介绍
  • 与本章中涉及的其他命令不一样,printf 命令并不适用于管道传输 (也就是说它不支持标准输入) ,而且命令行应用中它也不常见 (多用于脚本文件) 。
  • printf 起初是为 C 语言开发的,后来许多编程语言也都实现了这一功能,也包括 shell 环境。
  • 事实上,在 bash 中,printf 是内置的。
  • printf 的用法如下:
    1
    printf "format" arguments
  • 该命令行给出了一个包含格式说明的字符串,然后将该格式应用于 arguments 所代表的输入内容,最后格式化结果送至标准输出。
  • 下面就是一个简单的例子
    1
    2
    [me@linuxbox ~]$ printf "I formatted the string: %s\n" foo
    I formatted the string: foo
  • 该格式化字符串可以包含文字文本、转义字符以及以 % 开头的表示转换规格的字符序列。
  • 上例中,转换规格 %s 所代表的转换规格被字符串 foo 取代。
  • s 表示格式化字符串数据,其他类型的数据则用其他指定字符表示。
  1. 常用 printf 数据类型指定符
指定符 说明
D 将一个数字格式化为有符号的十进制表示形式
F 格式化数字并以浮点数的格式输出
O 将一个整数格式化为八进制格式的整数
s 格式化字符串
x 将一个整数格式化为十六进制的数,并且在使用字母时,用小写字母
X 与 x 类似,只是字母用大写字母表示
% 打印文字符号 %
  1. printf 案例
  • 下列中,利用字符串 “380” 演示了每个转换说明符的使用效果。
    1
    2
    [me@linuxbox ~]$ printf "%d, %f, %o, %s, %x, %X\n" 380 380 380 380 380 380
    380, 380.000000, 574, 380, 17c, 17C
  • 转换说明符也可以通过增加一些可选组件以对输出效果进行调整。一个完整的转换规格可能会包含如下内容:
    1
    %[flags][width][.precision]conversion_specification
  • 当使用多个可选组件时,这些组件必须按照上面顺序才能被正确编译。
  1. printf 转换规范组成部分
组件 功能描述
flags 总共有 5 个不同的 flag:# 使用替代格式输出。这取决于数据类型。对于 o (八进制数) 类转换,输出结果以 0 开头。对于 x 和 X 类转换,输出则分别以 0x 和 0X 开头;用 0 填充输出。这代表着字段前会填充 0,如 000380 ; - 表示输出左对齐。默认情况下, printf 是右对齐输出的;空格为正数产生一个前导空格; + 表示正数符号。默认情况下, printf 只会输出负数的符号
width 一个数字,该数字指定了最小字段宽度
.precision 对于浮点数,便是指定小数点后的小数精确度。对于字符串转换,precision 则指定了输出字符的个数
  1. printf 转换规范实例
参数 格式 转换结果 说明
380 “%d” 380 对整数进行简单的格式化
380 “%#x” 0x17c 使用替代格式标记将整数格式化为一个十六进制数
380 “%05d” 00380 将整数格式化为至少 5 字符宽度的字段,不足位数可在前面填充 0
380 “%05.5f” 380.00000 将数字格式化为精确到小数点后五位的浮点数,不足位数用 0 填充。由于指定的最小字段宽度 5 要比格式化后实际的数值位数小,所以此处并没有进行填充
380 “%010.5f” 0380.00000 把最小字段宽度增加为 10 ,并且 0 填充可见
380 “%+d” +380 + 标记符表示此数是正数
380 “%-d” 380 - 标记符表示左对齐
abcdefghijk “%5s” abcdefghijk 用最小的字段宽度来最小化字符串
abcdefghijk “%.5s” abcde 根据字符串的精确位数截断字符串
  1. printf 补充说明
  • 同样,printf 通常用于脚本文件的表格数据格式化操作,而并不会直接应用于命令行。
  • 不过,我们仍然可以用其解决各种各样的格式化问题。
  • 首先我们可以利用 printf 输出一些由制表符隔开的字段。
    1
    2
    [me@linuxbox ~]$ printf "%s\t%s\t%s\n" str1 str2 str3
    str1 str2 str3

参考文章

  • 转载:Linux 命令行大全