在這章中,我們繼續(xù)著手于文本相關(guān)的工具,關(guān)注那些用來格式化輸出的程序,而不是改變文本自身。 這些工具通常讓文本準(zhǔn)備就緒打印,這是我們在下一章會提到的。我們在這章中會提到的工具有:
> * nl – 添加行號
> * fold – 限制文件列寬
> * fmt – 一個簡單的文本格式轉(zhuǎn)換器
> * pr – 讓文本為打印做好準(zhǔn)備
> * printf – 格式化數(shù)據(jù)并打印出來
> * groff – 一個文件格式系統(tǒng)
## 簡單的格式化工具
我們將先著眼于一些簡單的格式工具。他們都是功能單一的程序,并且做法有一點(diǎn)單純, 但是他們能被用于小任務(wù)并且作為腳本和管道的一部分 。
### nl - 添加行號
nl 程序是一個相當(dāng)神秘的工具,用作一個簡單的任務(wù)。它添加文件的行數(shù)。在它最簡單的用途中,它相當(dāng)于 cat -n:
~~~
[me@linuxbox ~]$ nl distros.txt | head
~~~
像 cat,nl 既能接受多個文件作為命令行參數(shù),也能標(biāo)準(zhǔn)輸出。然而,nl 有一個相當(dāng)數(shù)量的選項(xiàng)并支持一個簡單的標(biāo)記方式去允許更多復(fù)雜的方式的計(jì)算。
nl 在計(jì)算文件行數(shù)的時候支持一個叫“邏輯頁面”的概念 。這允許nl在計(jì)算的時候去重設(shè)(再一次開始)可數(shù)的序列。用到那些選項(xiàng) 的時候,可以設(shè)置一個特殊的開始值,并且在某個可限定的程度上還能設(shè)置它的格式。一個邏輯頁面被進(jìn)一步分為 header,body 和 footer 這樣的元素。在每一個部分中,數(shù)行數(shù)可以被重設(shè),并且/或被設(shè)置成另外一個格式。如果nl同時處理多個文件,它會把他們當(dāng)成一個單一的 文本流。文本流中的部分被一些相當(dāng)古怪的標(biāo)記的存在加進(jìn)了文本:
每一個上述的標(biāo)記元素肯定在自己的行中獨(dú)自出現(xiàn)。在處理完一個標(biāo)記元素之后,nl 把它從文本流中刪除。
這里有一些常用的 nl 選項(xiàng):
表格 22-2: 常用 nl 選項(xiàng)
| 選項(xiàng) | 含義 |
|-----|-------|
| -b style | 把 body 按被要求方式數(shù)行,可以是以下方式:a = 數(shù)所有行 t = 數(shù)非空行。這是默認(rèn)設(shè)置。n = 無 pregexp = 只數(shù)那些匹配了正則表達(dá)式的行 |
| -f style | 將 footer 按被要求設(shè)置數(shù)。默認(rèn)是無 |
| -h style | 將 header 按被要求設(shè)置數(shù)。默認(rèn)是 |
| -i number | 將頁面增加量設(shè)置為數(shù)字。默認(rèn)是一。 |
| -n format | 設(shè)置數(shù)數(shù)的格式,格式可以是:ln = 左偏,沒有前導(dǎo)零。rn = 右偏,沒有前導(dǎo)零。rz = 右偏,有前導(dǎo)零。 |
| -p | 不要在沒一個邏輯頁面的開始重設(shè)頁面數(shù)。 |
| -s string | 在沒一個行的末尾加字符作分割符號。默認(rèn)是單個的 tab。 |
| -v number | 將每一個邏輯頁面的第一行設(shè)置成數(shù)字。默認(rèn)是一。 |
| -w width | 將行數(shù)的寬度設(shè)置,默認(rèn)是六。 |
坦誠的說,我們大概不會那么頻繁地去數(shù)行數(shù),但是我們能用 nl 去查看我們怎么將多個工具結(jié)合在一個去完成更復(fù)雜的任務(wù)。 我們將在之前章節(jié)的基礎(chǔ)上做一個 Linux 發(fā)行版的報(bào)告。因?yàn)槲覀儗⑹褂?nl,包含它的 header/body/footer 標(biāo)記將會十分有用。 我們將把它加到上一章的 sed 腳本來做這個。使用我們的文本編輯器,我們將腳本改成一下并且把它保存成 distros-nl.sed:
~~~
# sed script to produce Linux distributions report
1 i\
\\:\\:\\:\
\
Linux Distributions Report\
\
Name
Ver. Released\
----
---- --------\
\\:\\:
s/\([0-9]\{2\}\)\/\([0-9]\{2\}\)\/\([0-9]\{4\}\)$/\3-\1-\2/
$ i\
\\:\
\
End Of Report
~~~
這個腳本現(xiàn)在加入了 nl 的邏輯頁面標(biāo)記并且在報(bào)告的最后加了一個 footer。記得我們在我們的標(biāo)記中必須兩次使用反斜杠, 因?yàn)樗麄兺ǔ1?sed 解釋成一個轉(zhuǎn)義字符。
下一步,我們將結(jié)合 sort, sed, nl 來生成我們改進(jìn)的報(bào)告:
~~~
[me@linuxbox ~]$ sort -k 1,1 -k 2n distros.txt | sed -f distros-nl.sed | nl
Linux Distributions Report
Name Ver. Released
---- ---- --------
1 Fedora 5 2006-03-20
2 Fedora 6 2006-10-24
3 Fedora 7 2007-05-31
4 Fedora 8 2007-11-08
5 Fedora 9 2008-05-13
6 Fedora 10 2008-11-25
7 SUSE 10.1 2006-05-11
8 SUSE 10.2 2006-12-07
9 SUSE 10.3 2007-10-04
10 SUSE 11.0 2008-06-19
11 Ubuntu 6.06 2006-06-01
12 Ubuntu 6.10 2006-10-26
13 Ubuntu 7.04 2007-04-19
14 Ubuntu 7.10 2007-10-18
15 Ubuntu 8.04 2008-04-24
End Of Report
~~~
我們的報(bào)告是一串命令的結(jié)果,首先,我們給名單按發(fā)行版本和版本號(表格1和2處)進(jìn)行排序,然后我們用 sed 生產(chǎn)結(jié)果, 增加了 header(包括了為 nl 增加的邏輯頁面標(biāo)記)和 footer。最后,我們按默認(rèn)用 nl 生成了結(jié)果,只數(shù)了屬于邏輯頁面的 body 部分的 文本流的行數(shù)。
我們能夠重復(fù)命令并且實(shí)驗(yàn)不同的 nl 選項(xiàng)。一些有趣的方式:
~~~
nl -n rz
~~~
和
~~~
nl -w 3 -s ' '
~~~
### fold - 限制文件行寬
折疊是將文本的行限制到特定的寬的過程。像我們的其他命令,fold 接受一個或多個文件及標(biāo)準(zhǔn)輸入。如果我們將 一個簡單的文本流 fold,我們可以看到它工具的方式:
~~~
[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.
~~~
這里我們看到了 fold 的行為。這個用 echo 命令發(fā)送的文本用 -w 選項(xiàng)分解成塊。在這個例子中,我們設(shè)定了行寬為12個字符。 如果沒有字符設(shè)置,默認(rèn)是80。注意到文本行不會因?yàn)閱卧~邊界而不會被分解。增加的 -s 選項(xiàng)將讓 fold 分解到最后可用的空白 字符,即會考慮單詞邊界。
~~~
[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 - 一個簡單的文本格式器
fmt 程序同樣折疊文本,外加很多功能。它接受文本或標(biāo)準(zhǔn)輸入并且在文本流上呈現(xiàn)照片轉(zhuǎn)換。基礎(chǔ)來說,他填補(bǔ)并且將文本粘帖在 一起并且保留了空白符和縮進(jìn)。
為了解釋,我們將需要一些文本。讓我們抄一些 fmt 主頁上的東西吧:
我們將把這段文本復(fù)制進(jìn)我們的文本編輯器并且保存文件名為 fmt-info.txt?,F(xiàn)在,讓我們重新格式這個文本并且讓它成為一個50 個字符寬的項(xiàng)目。我們能用 -w 選項(xiàng)對文件進(jìn)行處理:
~~~
[me@linuxbox ~]$ fmt -w 50 fmt-info.txt | head
'fmt' reads from the specified FILE arguments
(or standard input if
none are given), and writes to standard output.
By default, blank lines, spaces between words,
and indentation are
preserved in the output; successive input lines
with different indentation are not joined; tabs
are expanded on input and introduced on output.
~~~
好,這真是一個奇怪的結(jié)果。大概我們應(yīng)該認(rèn)真的閱讀這段文本,因?yàn)樗『媒忉屃税l(fā)生了什么:
默認(rèn)來說,空白行,單詞間距,還有縮進(jìn)都會在輸出中保留;持續(xù)輸入不同的縮進(jìn)的流不會被結(jié)合;tabs被用來擴(kuò)展 輸入并且引入輸出。
所以,fmt 保留了第一行的縮進(jìn)。幸運(yùn)的是,fmt 提供一個修正這個的選項(xiàng):
好多了。通過加了 -c 選項(xiàng),我們現(xiàn)在有了我們想要的結(jié)果。
fmt 有一些有趣的選項(xiàng):
-p 選項(xiàng)特別有趣。通過它,我們可以格式文件選中的部分,通過在開頭使用一樣的符號。 很多編程語言使用錨標(biāo)記(#)去提醒注釋的開始,而且它可以通過這個選項(xiàng)來被格式。讓我們創(chuàng)建一個有用到注釋的程序。
~~~
[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.
~~~
我們的示例文件包含了用 “#” 開始的注釋(一個 # 后跟著一個空白符)和代碼?,F(xiàn)在,使用 fmt,我們能格式注釋并且 不讓代碼被觸及。
- 第一章:引言
- 第二章:什么是shell
- 第三章:文件系統(tǒng)中跳轉(zhuǎn)
- 第四章:研究操作系統(tǒng)
- 第五章:操作文件和目錄
- 第六章:使用命令
- 第七章:重定向
- 第八章:從shell眼中看世界
- 第九章:鍵盤高級操作技巧
- 第十章:權(quán)限
- 第十一章:進(jìn)程
- 第十二章:shell環(huán)境
- 第十三章:VI簡介
- 第十四章:自定制shell提示符
- 第十五章:軟件包管理
- 第十六章:存儲媒介
- 第十七章:網(wǎng)絡(luò)系統(tǒng)
- 第十八章:查找文件
- 第十九章:歸檔和備份
- 第二十章:正則表達(dá)式
- 第二十一章:文本處理
- 第二十二章:格式化輸出
- 第二十三章:打印
- 第二十四章:編譯程序
- 第二十五章:編寫第一個shell腳本
- 第二十六章:啟動一個項(xiàng)目
- 第二十七章:自頂向下設(shè)計(jì)
- 第二十八章:流程控制 if分支結(jié)構(gòu)
- 第二十九章:讀取鍵盤輸入
- 第三十章:流程控制 while/until 循環(huán)
- 第三十一章:疑難排解
- 第三十二章:流程控制 case分支
- 第三十三章:位置參數(shù)
- 第三十四章:流程控制 for循環(huán)
- 第三十五章:字符串和數(shù)字
- 第三十六章:數(shù)組
- 第三十七章:奇珍異寶
