## 11.4 文件的格式化與相關處理
接下來讓我們來將文件進行一些簡單的編排吧!下面這些動作可以將你的訊息進行排版的動作, 不需要重新以 vim 去編輯,通過數據流重導向配合下面介紹的 printf 功能,以及 awk 指令, 就可以讓你的訊息以你想要的模樣來輸出了!試看看吧!
### 11.4.1 格式化打印: printf
在很多時候,我們可能需要將自己的數據給他格式化輸出的! 舉例來說,考試卷分數的輸出,姓名與科目及分數之間,總是可以稍微作個比較漂亮的版面配置吧? 例如我想要輸出下面的樣式:
```
Name Chinese English Math Average
DmTsai 80 60 92 77.33
VBird 75 55 80 70.00
Ken 60 90 70 73.33
```
上表的數據主要分成五個字段,各個字段之間可使用 tab 或空白鍵進行分隔。 請將上表的數據轉存成為 printf.txt 文件名,等一下我們會利用這個文件來進行幾個小練習的。 因為每個字段的原始數據長度其實并非是如此固定的 (Chinese 長度就是比 Name 要多), 而我就是想要如此表示出這些數據,此時,就得需要打印格式管理員 printf 的幫忙了! printf 可以幫我們將數據輸出的結果格式化,而且而支持一些特殊的字符~下面我們就來看看!
```
[dmtsai@study ~]$ printf '打印格式' 實際內容
選項與參數:
關于格式方面的幾個特殊樣式:
\a 警告聲音輸出
\b 倒退鍵(backspace)
\f 清除屏幕 (form feed)
\n 輸出新的一行
\r 亦即 Enter 按鍵
\t 水平的 [tab] 按鍵
\v 垂直的 [tab] 按鍵
\xNN NN 為兩位數的數字,可以轉換數字成為字符。
關于 C 程序語言內,常見的變量格式
%ns 那個 n 是數字, s 代表 string ,亦即多少個字符;
%ni 那個 n 是數字, i 代表 integer ,亦即多少整數碼數;
%N.nf 那個 n 與 N 都是數字, f 代表 floating (浮點),如果有小數碼數,
假設我共要十個位數,但小數點有兩位,即為 %10.2f 啰!
```
接下來我們來進行幾個常見的練習。假設所有的數據都是一般文字 (這也是最常見的狀態),因此最常用來分隔數據的符號就是 [Tab] 啦!因為 [Tab] 按鍵可以將數據作個整齊的排列!那么如何利用 printf 呢?參考下面這個范例:
```
范例一:將剛剛上頭數據的文件 (printf.txt) 內容僅列出姓名與成績:(用 [tab] 分隔)
[dmtsai@study ~]$ printf '%s\t %s\t %s\t %s\t %s\t \n' $(cat printf.txt)
Name Chinese English Math Average
DmTsai 80 60 92 77.33
VBird 75 55 80 70.00
Ken 60 90 70 73.33
```
由于 printf 并不是管線命令,因此我們得要通過類似上面的功能,將文件內容先提出來給 printf 作為后續的數據才行。 如上所示,我們將每個數據都以 [tab] 作為分隔,但是由于 Chinese 長度太長,導致 English 中間多了一個 [tab] 來將數據排列整齊!啊~結果就看到數據對齊結果的差異了!
另外,在 printf 后續的那一段格式中,%s 代表一個不固定長度的字串,而字串與字串中間就以 \t 這個 [tab] 分隔符號來處理!你要記得的是,由于 \t 與 %s 中間還有空格,因此每個字串間會有一個 [tab] 與一個空白鍵的分隔喔!
既然每個字段的長度不固定會造成上述的困擾,那我將每個字段固定就好啦!沒錯沒錯!這樣想非常好! 所以我們就將數據給他進行固定字段長度的設計吧!
```
范例二:將上述數據關于第二行以后,分別以字串、整數、小數點來顯示:
[dmtsai@study ~]$ printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt | grep -v Name)
DmTsai 80 60 92 77.33
VBird 75 55 80 70.00
Ken 60 90 70 73.33
```
上面這一串格式想必您看得很辛苦!沒關系!一個一個來解釋!上面的格式共分為五個字段, %10s 代表的是一個長度為 10 個字符的字串字段,%5i 代表的是長度為 5 個字符的數字字段,至于那個 %8.2f 則代表長度為 8 個字符的具有小數點的字段,其中小數點有兩個字符寬度。我們可以使用下面的說明來介紹 %8.2f 的意義:
> 字符寬度: 12345678
> %8.2f意義:00000.00
如上所述,全部的寬度僅有 8 個字符,整數部分占有 5 個字符,小數點本身 (.) 占一位,小數點下的位數則有兩位。 這種格式經常使用于數值程序的設計中!這樣了解乎?自己試看看如果要將小數點位數變成 1 位又該如何處理?
printf 除了可以格式化處理之外,他還可以依據 ASCII 的數字與圖形對應來顯示數據喔[[3]](#ps3)! 舉例來說 16 進位的 45 可以得到什么 ASCII 的顯示圖 (其實是字符啦)?
```
范例三:列出 16 進位數值 45 代表的字符為何?
[dmtsai@study ~]$ printf '\x45\n'
E
# 這東西也很好玩~他可以將數值轉換成為字符,如果你會寫 script 的話,
# 可以自行測試一下,由 20~80 之間的數值代表的字符是啥喔! ^_^
```
printf 的使用相當的廣泛喔!包括等一下后面會提到的 awk 以及在 C 程序語言當中使用的屏幕輸出, 都是利用 printf 呢!鳥哥這里也只是列出一些可能會用到的格式而已,有興趣的話,可以自行多作一些測試與練習喔! ^_^

**Tips** 打印格式化這個 printf 指令,乍看之下好像也沒有什么很重要的~ 不過,如果你需要自行撰寫一些軟件,需要將一些數據在屏幕上頭漂漂亮亮的輸出的話, 那么 printf 可也是一個很棒的工具喔!
### 11.4.2 awk:好用的數據處理工具
awk 也是一個非常棒的數據處理工具!相較于 sed 常常作用于一整個行的處理, awk 則比較傾向于一行當中分成數個“字段”來處理。因此,awk 相當的適合處理小型的數據數據處理呢!awk 通常運行的模式是這樣的:
```
[dmtsai@study ~]$ awk '條件類型1{動作1} 條件類型2{動作2} ...' filename
```
awk 后面接兩個單引號并加上大括號 {} 來設置想要對數據進行的處理動作。 awk 可以處理后續接的文件,也可以讀取來自前個指令的 standard output 。 但如前面說的, awk 主要是處理“每一行的字段內的數據”,而默認的“字段的分隔符號為 "空白鍵" 或 "[tab]鍵" ”!舉例來說,我們用 last 可以將登陸者的數據取出來,結果如下所示:
```
[dmtsai@study ~]$ last -n 5 <==僅取出前五行
dmtsai pts/0 192.168.1.100 Tue Jul 14 17:32 still logged in
dmtsai pts/0 192.168.1.100 Thu Jul 9 23:36 - 02:58 (03:22)
dmtsai pts/0 192.168.1.100 Thu Jul 9 17:23 - 23:36 (06:12)
dmtsai pts/0 192.168.1.100 Thu Jul 9 08:02 - 08:17 (00:14)
dmtsai tty1 Fri May 29 11:55 - 12:11 (00:15)
```
若我想要取出帳號與登陸者的 IP ,且帳號與 IP 之間以 [tab] 隔開,則會變成這樣:
```
[dmtsai@study ~]$ last -n 5 | awk '{print $1 "\t" $3}'
dmtsai 192.168.1.100
dmtsai 192.168.1.100
dmtsai 192.168.1.100
dmtsai 192.168.1.100
dmtsai Fri
```
上表是 awk 最常使用的動作!通過 print 的功能將字段數據列出來!字段的分隔則以空白鍵或 [tab] 按鍵來隔開。 因為不論哪一行我都要處理,因此,就不需要有 "條件類型" 的限制!我所想要的是第一欄以及第三欄, 但是,第五行的內容怪怪的~這是因為數據格式的問題啊!所以啰~使用 awk 的時候,請先確認一下你的數據當中,如果是連續性的數據,請不要有空格或 [tab] 在內,否則,就會像這個例子這樣,會發生誤判喔!
另外,由上面這個例子你也會知道,在 awk 的括號內,每一行的每個字段都是有變量名稱的,那就是 $1, $2... 等變量名稱。以上面的例子來說, dmtsai 是 $1 ,因為他是第一欄嘛!至于 192.168.1.100 是第三欄, 所以他就是 $3 啦!后面以此類推~呵呵!還有個變量喔!那就是 $0 ,$0 代表“一整列數據”的意思~以上面的例子來說,第一行的 $0 代表的就是“dmtsai .... ”那一行啊! 由此可知,剛剛上面五行當中,整個 awk 的處理流程是:
1. 讀入第一行,并將第一行的數據填入 $0, $1, $2.... 等變量當中;
2. 依據 "條件類型" 的限制,判斷是否需要進行后面的 "動作";
3. 做完所有的動作與條件類型;
4. 若還有后續的“行”的數據,則重復上面 1~3 的步驟,直到所有的數據都讀完為止。
經過這樣的步驟,你會曉得, awk 是“以行為一次處理的單位”, 而“以字段為最小的處理單位”。好了,那么 awk 怎么知道我到底這個數據有幾行?有幾欄呢?這就需要 awk 的內置變量的幫忙啦~
| 變量名稱 | 代表意義 |
| --- | --- |
| NF | 每一行 ($0) 擁有的字段總數 |
| NR | 目前 awk 所處理的是“第幾行”數據 |
| FS | 目前的分隔字符,默認是空白鍵 |
我們繼續以上面 last -n 5 的例子來做說明,如果我想要:
* 列出每一行的帳號(就是 $1);
* 列出目前處理的行數(就是 awk 內的 NR 變量)
* 并且說明,該行有多少字段(就是 awk 內的 NF 變量)
則可以這樣:

**Tips** 要注意喔,awk 后續的所有動作是以單引號“ ' ”括住的,由于單引號與雙引號都必須是成對的, 所以, awk 的格式內容如果想要以 print 打印時,記得非變量的文字部分,包含上一小節 [printf](../Text/index.html#printf) 提到的格式中,都需要使用雙引號來定義出來喔!因為單引號已經是 awk 的指令固定用法了!
```
[dmtsai@study ~]$ last -n 5| awk '{print $1 "\t lines: " NR "\t columns: " NF}'
dmtsai lines: 1 columns: 10
dmtsai lines: 2 columns: 10
dmtsai lines: 3 columns: 10
dmtsai lines: 4 columns: 10
dmtsai lines: 5 columns: 9
# 注意喔,在 awk 內的 NR, NF 等變量要用大寫,且不需要有錢字號 $ 啦!
```
這樣可以了解 NR 與 NF 的差別了吧?好了,下面來談一談所謂的 "條件類型" 了吧!
* awk 的邏輯運算字符
既然有需要用到 "條件" 的類別,自然就需要一些邏輯運算啰~例如下面這些:
| 運算單元 | 代表意義 |
| --- | --- |
| > | 大于 |
| < | 小于 |
| >= | 大于或等于 |
| <= | 小于或等于 |
| == | 等于 |
| != | 不等于 |
值得注意的是那個“ == ”的符號,因為:
* 邏輯運算上面亦即所謂的大于、小于、等于等判斷式上面,習慣上是以“ == ”來表示;
* 如果是直接給予一個值,例如變量設置時,就直接使用 = 而已。
好了,我們實際來運用一下邏輯判斷吧!舉例來說,在 /etc/passwd 當中是以冒號 ":" 來作為字段的分隔, 該文件中第一字段為帳號,第三字段則是 UID。那假設我要查閱,第三欄小于 10 以下的數據,并且僅列出帳號與第三欄, 那么可以這樣做:
```
[dmtsai@study ~]$ cat /etc/passwd | awk '{FS=":"} $3 < 10 {print $1 "\t " $3}'
root:x:0:0:root:/root:/bin/bash
bin 1
daemon 2
....(以下省略)....
```
有趣吧!不過,怎么第一行沒有正確的顯示出來呢?這是因為我們讀入第一行的時候,那些變量 $1, $2... 默認還是以空白鍵為分隔的,所以雖然我們定義了 FS=":" 了, 但是卻僅能在第二行后才開始生效。那么怎么辦呢?我們可以預先設置 awk 的變量啊! 利用 BEGIN 這個關鍵字喔!這樣做:
```
[dmtsai@study ~]$ cat /etc/passwd | awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}'
root 0
bin 1
daemon 2
......(以下省略)......
```
很有趣吧!而除了 BEGIN 之外,我們還有 END 呢!另外,如果要用 awk 來進行“計算功能”呢?以下面的例子來看, 假設我有一個薪資數據表文件名為 pay.txt ,內容是這樣的:
```
Name 1st 2nd 3th
VBird 23000 24000 25000
DMTsai 21000 20000 23000
Bird2 43000 42000 41000
```
如何幫我計算每個人的總額呢?而且我還想要格式化輸出喔!我們可以這樣考慮:
* 第一行只是說明,所以第一行不要進行加總 (NR==1 時處理);
* 第二行以后就會有加總的情況出現 (NR>=2 以后處理)
```
[dmtsai@study ~]$ cat pay.txt | \
> awk 'NR==1{printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total" }
> NR>=2{total = $2 + $3 + $4
> printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
Name 1st 2nd 3th Total
VBird 23000 24000 25000 72000.00
DMTsai 21000 20000 23000 64000.00
Bird2 43000 42000 41000 126000.00
```
上面的例子有幾個重要事項應該要先說明的:
* awk 的指令間隔:所有 awk 的動作,亦即在 {} 內的動作,如果有需要多個指令輔助時,可利用分號“;”間隔, 或者直接以 [Enter] 按鍵來隔開每個指令,例如上面的范例中,鳥哥共按了三次 [enter] 喔!
* 邏輯運算當中,如果是“等于”的情況,則務必使用兩個等號“==”!
* 格式化輸出時,在 printf 的格式設置當中,務必加上 \n ,才能進行分行!
* 與 bash shell 的變量不同,在 awk 當中,變量可以直接使用,不需加上 $ 符號。
利用 awk 這個玩意兒,就可以幫我們處理很多日常工作了呢!真是好用的很~ 此外, awk 的輸出格式當中,常常會以 [printf](../Text/index.html#printf) 來輔助,所以, 最好你對 printf 也稍微熟悉一下比較好啦!另外, awk 的動作內 {} 也是支持 if (條件) 的喔! 舉例來說,上面的指令可以修訂成為這樣:
```
[dmtsai@study ~]$ cat pay.txt | \
> awk '{if(NR==1) printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total"}
> NR>=2{total = $2 + $3 + $4
> printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
```
你可以仔細的比對一下上面兩個輸入有啥不同~從中去了解兩種語法吧!我個人是比較傾向于使用第一種語法, 因為會比較有統一性啊! ^_^
除此之外, awk 還可以幫我們進行循環計算喔!真是相當的好用!不過,那屬于比較進階的單獨課程了, 我們這里就不再多加介紹。如果你有興趣的話,請務必參考延伸閱讀中的相關鏈接喔 [[4]](#ps4)。
### 11.4.3 文件比對工具
什么時候會用到文件的比對啊?通常是“同一個套裝軟件的不同版本之間,比較配置文件與原始文件的差異”。 很多時候所謂的文件比對,通常是用在 ASCII 純文本文件的比對上的!那么比對文件的指令有哪些?最常見的就是 diff 啰! 另外,除了 diff 比對之外,我們還可以借由 cmp 來比對非純文本文件!同時,也能夠借由 diff 創建的分析檔, 以處理補丁 (patch) 功能的文件呢!就來玩玩先!
* diff
diff 就是用在比對兩個文件之間的差異的,并且是以行為單位來比對的!一般是用在 ASCII 純文本文件的比對上。 由于是以行為比對的單位,因此 diff 通常是用在同一的文件(或軟件)的新舊版本差異上! 舉例來說,假如我們要將 /etc/passwd 處理成為一個新的版本,處理方式為: 將第四行刪除,第六行則取代成為“no six line”,新的文件放置到 /tmp/test 里面,那么應該怎么做?
```
[dmtsai@study ~]$ mkdir -p /tmp/testpw <==先創建測試用的目錄
[dmtsai@study ~]$ cd /tmp/testpw
[dmtsai@study testpw]$ cp /etc/passwd passwd.old
[dmtsai@study testpw]$ cat /etc/passwd | sed -e '4d' -e '6c no six line' > passwd.new
# 注意一下, sed 后面如果要接超過兩個以上的動作時,每個動作前面得加 -e 才行!
# 通過這個動作,在 /tmp/testpw 里面便有新舊的 passwd 文件存在了!
```
接下來討論一下關于 diff 的用法吧!
```
[dmtsai@study ~]$ diff [-bBi] from-file to-file
選項與參數:
from-file :一個文件名,作為原始比對文件的文件名;
to-file :一個文件名,作為目的比對文件的文件名;
注意,from-file 或 to-file 可以 - 取代,那個 - 代表“Standard input”之意。
-b :忽略一行當中,僅有多個空白的差異(例如 "about me" 與 "about me" 視為相同
-B :忽略空白行的差異。
-i :忽略大小寫的不同。
范例一:比對 passwd.old 與 passwd.new 的差異:
[dmtsai@study testpw]$ diff passwd.old passwd.new
4d3 <==左邊第四行被刪除 (d) 掉了,基準是右邊的第三行
< adm:x:3:4:adm:/var/adm:/sbin/nologin <==這邊列出左邊(<)文件被刪除的那一行內容
6c5 <==左邊文件的第六行被取代 (c) 成右邊文件的第五行
< sync:x:5:0:sync:/sbin:/bin/sync <==左邊(<)文件第六行內容
---
> no six line <==右邊(>)文件第五行內容
# 很聰明吧!用 diff 就把我們剛剛的處理給比對完畢了!
```
用 diff 比對文件真的是很簡單喔!不過,你不要用 diff 去比對兩個完全不相干的文件,因為比不出個啥咚咚! 另外, diff 也可以比對整個目錄下的差異喔!舉例來說,我們想要了解一下不同的開機執行等級 (runlevel) 內容有啥不同?假設你已經知道執行等級 0 與 5 的啟動腳本分別放置到 /etc/rc0.d 及 /etc/rc5.d , 則我們可以將兩個目錄比對一下:
```
[dmtsai@study ~]$ diff /etc/rc0.d/ /etc/rc5.d/
Only in /etc/rc0.d/: K90network
Only in /etc/rc5.d/: S10network
```
我們的 diff 很聰明吧!還可以比對不同目錄下的相同文件名的內容,這樣真的很方便喔~
* cmp
相對于 diff 的廣泛用途, cmp 似乎就用的沒有這么多了~ cmp 主要也是在比對兩個文件,他主要利用“字節”單位去比對, 因此,當然也可以比對 binary file 啰~(還是要再提醒喔, diff 主要是以“行”為單位比對, cmp 則是以“字節”為單位去比對,這并不相同!)
```
[dmtsai@study ~]$ cmp [-l] file1 file2
選項與參數:
-l :將所有的不同點的字節處都列出來。因為 cmp 默認僅會輸出第一個發現的不同點。
范例一:用 cmp 比較一下 passwd.old 及 passwd.new
[dmtsai@study testpw]$ cmp passwd.old passwd.new
passwd.old passwd.new differ: char 106, line 4
```
看到了嗎?第一個發現的不同點在第四行,而且字節數是在第 106 個字節處!這個 cmp 也可以用來比對 binary 啦! ^_^
* patch
patch 這個指令與 diff 可是有密不可分的關系啊!我們前面提到,diff 可以用來分辨兩個版本之間的差異, 舉例來說,剛剛我們所創建的 passwd.old 及 passwd.new 之間就是兩個不同版本的文件。 那么,如果要“升級”呢?就是“將舊的文件升級成為新的文件”時,應該要怎么做呢? 其實也不難啦!就是“先比較先舊版本的差異,并將差異檔制作成為補丁文件,再由補丁文件更新舊文件”即可。 舉例來說,我們可以這樣做測試:
```
范例一:以 /tmp/testpw 內的 passwd.old 與 passwd.new 制作補丁文件
[dmtsai@study testpw]$ diff -Naur passwd.old passwd.new > passwd.patch
[dmtsai@study testpw]$ cat passwd.patch
--- passwd.old 2015-07-14 22:37:43.322535054 +0800 <==新舊文件的信息
+++ passwd.new 2015-07-14 22:38:03.010535054 +0800
@@ -1,9 +1,8 @@ <==新舊文件要修改數據的界定范圍,舊文件在 1-9 行,新文件在 1-8 行
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
-adm:x:3:4:adm:/var/adm:/sbin/nologin <==左側文件刪除
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
-sync:x:5:0:sync:/sbin:/bin/sync <==左側文件刪除
+no six line <==右側新文件加入
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
```
一般來說,使用 diff 制作出來的比較文件通常使用擴展名為 .patch 啰。至于內容就如同上面介紹的樣子。 基本上就是以行為單位,看看哪邊有一樣與不一樣的,找到一樣的地方,然后將不一樣的地方取代掉! 以上面表格為例,新文件看到 - 會刪除,看到 + 會加入!好了,那么如何將舊的文件更新成為新的內容呢? 就是將 passwd.old 改成與 passwd.new 相同!可以這樣做:
```
# 因為 CentOS 7 默認沒有安裝 patch 這個軟件,因此得要依據之前介紹的方式來安裝一下軟件!
# 請記得拿出原本光盤并放入光驅當中,這時才能夠使用下面的方式來安裝軟件!
[dmtsai@study ~]$ su -
[root@study ~]# mount /dev/sr0 /mnt
[root@study ~]# rpm -ivh /mnt/Packages/patch-2.*
[root@study ~]# umount /mnt
[root@study ~]# exit
# 通過上述的方式可以安裝好所需要的軟件,且無須上網。接下來讓我們開始操作 patch 啰!
[dmtsai@study ~]$ patch -pN < patch_file <==更新
[dmtsai@study ~]$ patch -R -pN < patch_file <==還原
選項與參數:
-p :后面可以接“取消幾層目錄”的意思。
-R :代表還原,將新的文件還原成原來舊的版本。
范例二:將剛剛制作出來的 patch file 用來更新舊版數據
[dmtsai@study testpw]$ patch -p0 < passwd.patch
patching file passwd.old
[dmtsai@study testpw]$ ll passwd*
-rw-rw-r--. 1 dmtsai dmtsai 2035 Jul 14 22:38 passwd.new
-rw-r--r--. 1 dmtsai dmtsai 2035 Jul 14 23:30 passwd.old <==文件一模一樣!
范例三:恢復舊文件的內容
[dmtsai@study testpw]$ patch -R -p0 < passwd.patch
[dmtsai@study testpw]$ ll passwd*
-rw-rw-r--. 1 dmtsai dmtsai 2035 Jul 14 22:38 passwd.new
-rw-r--r--. 1 dmtsai dmtsai 2092 Jul 14 23:31 passwd.old
# 文件就這樣恢復成為舊版本啰
```
為什么這里會使用 -p0 呢?因為我們在比對新舊版的數據時是在同一個目錄下, 因此不需要減去目錄啦!如果是使用整體目錄比對 (diff 舊目錄 新目錄) 時, 就得要依據創建 patch 文件所在目錄來進行目錄的刪減啰!
更詳細的 patch 用法我們會在后續的第五篇的[源代碼編譯 (第二十一章)](../Text/index.html#tarball_patch)再跟大家介紹, 這里僅是介紹給你,我們可以利用 diff 來比對兩個文件之間的差異, 更可進一步利用這個功能來制作修補文件 (patch file) ,讓大家更容易進行比對與升級呢!很不賴吧! ^_^
### 11.4.4 文件打印準備: pr
如果你曾經使用過一些圖形接口的文書處理軟件的話,那么很容易發現,當我們在打印的時候, 可以同時選擇與設置每一頁打印時的標頭吧!也可以設置頁碼呢!那么,如果我是在 Linux 下面打印純文本文件呢 可不可以具有標題啊?可不可以加入頁碼啊?呵呵!當然可以啊!使用 pr 就能夠達到這個功能了。不過, pr 的參數實在太多了,鳥哥也說不完,一般來說,鳥哥都僅使用最簡單的方式來處理而已。舉例來說,如果想要打印 /etc/man_db.conf 呢?
```
[dmtsai@study ~]$ pr /etc/man_db.conf
2014-06-10 05:35 /etc/man_db.conf Page 1
#
#
# This file is used by the man-db package to configure the man and cat paths.
# It is also used to provide a manpath for those without one by examining
# configure script.
.....(以下省略)......
```
上面特殊字體那一行呢,其實就是使用 pr 處理后所造成的標題啦!標題中會有“文件時間”、“文件文件名”及“頁碼”三大項目。 更多的 pr 使用,請參考 pr 的說明啊! ^_^
- 鳥哥的Linux私房菜:基礎學習篇 第四版
- 目錄及概述
- 第零章、計算機概論
- 0.1 電腦:輔助人腦的好工具
- 0.2 個人電腦架構與相關設備元件
- 0.3 數據表示方式
- 0.4 軟件程序運行
- 0.5 重點回顧
- 0.6 本章習題
- 0.7 參考資料與延伸閱讀
- 第一章、Linux是什么與如何學習
- 1.1 Linux是什么
- 1.2 Torvalds的Linux發展
- 1.3 Linux當前應用的角色
- 1.4 Linux 該如何學習
- 1.5 重點回顧
- 1.6 本章習題
- 1.7 參考資料與延伸閱讀
- 第二章、主機規劃與磁盤分區
- 2.1 Linux與硬件的搭配
- 2.2 磁盤分區
- 2.3 安裝Linux前的規劃
- 2.4 重點回顧
- 2.5 本章習題
- 2.6 參考資料與延伸閱讀
- 第三章、安裝 CentOS7.x
- 3.1 本練習機的規劃--尤其是分區參數
- 3.2 開始安裝CentOS 7
- 3.3 多重開機安裝流程與管理(Option)
- 3.4 重點回顧
- 3.5 本章習題
- 3.6 參考資料與延伸閱讀
- 第四章、首次登陸與線上求助
- 4.1 首次登陸系統
- 4.2 文字模式下指令的下達
- 4.3 Linux系統的線上求助man page與info page
- 4.4 超簡單文書編輯器: nano
- 4.5 正確的關機方法
- 4.6 重點回顧
- 4.7 本章習題
- 4.8 參考資料與延伸閱讀
- 第五章、Linux 的文件權限與目錄配置
- 5.1 使用者與群組
- 5.2 Linux 文件權限概念
- 5.3 Linux目錄配置
- 5.4 重點回顧
- 5.5 本章練習
- 5.6 參考資料與延伸閱讀
- 第六章、Linux 文件與目錄管理
- 6.1 目錄與路徑
- 6.2 文件與目錄管理
- 6.3 文件內容查閱
- 6.4 文件與目錄的默認權限與隱藏權限
- 6.5 指令與文件的搜尋
- 6.6 極重要的復習!權限與指令間的關系
- 6.7 重點回顧
- 6.8 本章習題:
- 6.9 參考資料與延伸閱讀
- 第七章、Linux 磁盤與文件系統管理
- 7.1 認識 Linux 文件系統
- 7.2 文件系統的簡單操作
- 7.3 磁盤的分區、格式化、檢驗與掛載
- 7.4 設置開機掛載
- 7.5 內存交換空間(swap)之創建
- 7.6 文件系統的特殊觀察與操作
- 7.7 重點回顧
- 7.8 本章習題 - 第一題一定要做
- 7.9 參考資料與延伸閱讀
- 第八章、文件與文件系統的壓縮,打包與備份
- 8.1 壓縮文件的用途與技術
- 8.2 Linux 系統常見的壓縮指令
- 8.3 打包指令: tar
- 8.4 XFS 文件系統的備份與還原
- 8.5 光盤寫入工具
- 8.6 其他常見的壓縮與備份工具
- 8.7 重點回顧
- 8.8 本章習題
- 8.9 參考資料與延伸閱讀
- 第九章、vim 程序編輯器
- 9.1 vi 與 vim
- 9.2 vi 的使用
- 9.3 vim 的額外功能
- 9.4 其他 vim 使用注意事項
- 9.5 重點回顧
- 9.6 本章練習
- 9.7 參考資料與延伸閱讀
- 第十章、認識與學習BASH
- 10.1 認識 BASH 這個 Shell
- 10.2 Shell 的變量功能
- 10.3 命令別名與歷史命令
- 10.4 Bash Shell 的操作環境:
- 10.5 數據流重導向
- 10.6 管線命令 (pipe)
- 10.7 重點回顧
- 10.8 本章習題
- 10.9 參考資料與延伸閱讀
- 第十一章、正則表達式與文件格式化處理
- 11.1 開始之前:什么是正則表達式
- 11.2 基礎正則表達式
- 11.3 延伸正則表達式
- 11.4 文件的格式化與相關處理
- 11.5 重點回顧
- 11.6 本章習題
- 11.7 參考資料與延伸閱讀
- 第十二章、學習 Shell Scripts
- 12.1 什么是 Shell scripts
- 12.2 簡單的 shell script 練習
- 12.3 善用判斷式
- 12.4 條件判斷式
- 12.5 循環 (loop)
- 12.6 shell script 的追蹤與 debug
- 12.7 重點回顧
- 12.8 本章習題
- 第十三章、Linux 帳號管理與 ACL 權限設置
- 13.1 Linux 的帳號與群組
- 13.2 帳號管理
- 13.3 主機的細部權限規劃:ACL 的使用
- 13.4 使用者身份切換
- 13.5 使用者的特殊 shell 與 PAM 模塊
- 13.6 Linux 主機上的使用者訊息傳遞
- 13.7 CentOS 7 環境下大量創建帳號的方法
- 13.8 重點回顧
- 13.9 本章習題
- 13.10 參考資料與延伸閱讀
- 第十四章、磁盤配額(Quota)與進階文件系統管理
- 14.1 磁盤配額 (Quota) 的應用與實作
- 14.2 軟件磁盤陣列 (Software RAID)
- 14.3 邏輯卷軸管理員 (Logical Volume Manager)
- 14.4 重點回顧
- 14.5 本章習題
- 14.6 參考資料與延伸閱讀
- 第十五章、例行性工作調度(crontab)
- 15.1 什么是例行性工作調度
- 15.2 僅執行一次的工作調度
- 15.3 循環執行的例行性工作調度
- 15.4 可喚醒停機期間的工作任務
- 15.5 重點回顧
- 15.6 本章習題
- 第十六章、程序管理與 SELinux 初探
- 16.1 什么是程序 (process)
- 16.2 工作管理 (job control)
- 16.3 程序管理
- 16.4 特殊文件與程序
- 16.5 SELinux 初探
- 16.6 重點回顧
- 16.7 本章習題
- 16.8 參考資料與延伸閱讀
- 第十七章、認識系統服務 (daemons)
- 17.1 什么是 daemon 與服務 (service)
- 17.2 通過 systemctl 管理服務
- 17.3 systemctl 針對 service 類型的配置文件
- 17.4 systemctl 針對 timer 的配置文件
- 17.5 CentOS 7.x 默認啟動的服務簡易說明
- 17.6 重點回顧
- 17.7 本章習題
- 17.8 參考資料與延伸閱讀
- 第十八章、認識與分析登錄文件
- 18.1 什么是登錄文件
- 18.2 rsyslog.service :記錄登錄文件的服務
- 18.3 登錄文件的輪替(logrotate)
- 18.4 systemd-journald.service 簡介
- 18.5 分析登錄文件
- 18.6 重點回顧
- 18.7 本章習題
- 18.8 參考資料與延伸閱讀
- 第十九章、開機流程、模塊管理與 Loader
- 19.1 Linux 的開機流程分析
- 19.2 核心與核心模塊
- 19.3 Boot Loader: Grub2
- 19.4 開機過程的問題解決
- 19.5 重點回顧
- 19.6 本章習題
- 19.7 參考資料與延伸閱讀
- 第二十章、基礎系統設置與備份策略
- 20.1 系統基本設置
- 20.2 服務器硬件數據的收集
- 20.3 備份要點
- 20.4 備份的種類、頻率與工具的選擇
- 20.5 鳥哥的備份策略
- 20.6 災難復原的考慮
- 20.7 重點回顧
- 20.8 本章習題
- 20.9 參考資料與延伸閱讀
- 第二十一章、軟件安裝:源代碼與 Tarball
- 20.1 開放源碼的軟件安裝與升級簡介
- 21.2 使用傳統程序語言進行編譯的簡單范例
- 21.3 用 make 進行宏編譯
- 21.4 Tarball 的管理與建議
- 21.5 函數庫管理
- 21.6 檢驗軟件正確性
- 21.7 重點回顧
- 21.8 本章習題
- 21.9 參考資料與延伸閱讀
- 第二十二章、軟件安裝 RPM, SRPM 與 YUM
- 22.1 軟件管理員簡介
- 22.2 RPM 軟件管理程序: rpm
- 22.3 YUM 線上升級機制
- 22.4 SRPM 的使用 : rpmbuild (Optional)
- 22.5 重點回顧
- 22.6 本章習題
- 22.7 參考資料與延伸閱讀
- 第二十三章、X Window 設置介紹
- 23.1 什么是 X Window System
- 23.2 X Server 配置文件解析與設置
- 23.3 顯卡驅動程序安裝范例
- 23.4 重點回顧
- 23.5 本章習題
- 23.6 參考資料與延伸閱讀
- 第二十四章、Linux 核心編譯與管理
- 24.1 編譯前的任務:認識核心與取得核心源代碼
- 24.2 核心編譯的前處理與核心功能選擇
- 24.3 核心的編譯與安裝
- 24.4 額外(單一)核心模塊編譯
- 24.5 以最新核心版本編譯 CentOS 7.x 的核心
- 24.6 重點回顧
- 24.7 本章習題
- 24.8 參考資料與延伸閱讀