Linux之文本處理---cat、sort、uniq、cut、paste、join、comm、diff、patch、tr、sed、aspell

由於所有類UNIX操作系統都嚴重依賴於文本文件來進行某些數據類型的存儲,所以需要很多可以進行文本操作的工具.
常見的文本格式有

  • 文件:使用純文本格式編輯的文件。在使用文本格式編輯較大文件時,常用的方法是,首先在文本編輯器中編輯大型文檔的內容,然後使用標記語言描述文件格式。
  • 網頁:網頁屬於文本文檔,一般使用HTML(Hypertext Markup Language)或XML(eXtensible Markup Language)等標記語言描述內容的可視化.
  • 電子郵件:電子郵件本質上是一種基於文本的媒介,即便是非文本附件,在傳輸時候也會轉爲文本格式.
  • 打印機輸出:在類UNIX系統中,準備向打印機傳送的信息是以純文本格式傳送的。如果該頁包含圖像,則將其轉換成PostScript文本格式頁面描述語言再送至指定程序並打印圖像像素.
  • 程序源代碼:類UNIX很多命令行是爲了支持系統管理軟件開發。所有的軟件都是從文本開始,源代碼總是以文本形式編輯.

0.參考文獻

《Linux命令行大全》 [美] William E. Shotts. Jr 著 郭光偉 郝記生 譯, 人民郵電出版社

如有侵權,可聯繫博主刪除.
更多有用的Linux知識詳解,可參考我的Linux學習導航頁

1. cat—進行文本之間的拼接並且輸出到標準格式

cat我們已經在Linux命令行I/O重定向—重定向操作符、cat、管道、sort、uniq、wc、grep、head、tail、tee中講過基本用法,下面補充三個常用的選項.
-A選項用於顯示文本中的非打印字符,例如一些控制字符—(製表符和空格),另一種常見情況是文件中包含末尾帶有空格的文本行.
例如,輸入製表符+The qucik brown fox jumped over the lazy dog. 按下Ctrl+D結束的如下命令

$ cat > foo.txt
        The qucik brown fox jumped over the lazy dog.

得到一個以製表符開頭、空格符結尾的文本行.

$ cat -A foo.txt
^IThe qucik brown fox jumped over the lazy dog.$

文本中的Tab製表符由符號"^I“表示,意思是"Ctrl+I”.在文件末尾出現的"$"符說明行末尾存在空格.
-n選項用於對行編號,’-s’選項用於禁止輸出多個空白行.

2. sort—對文本行進行排序

sort是一個排序程序.

$ sort > foo.txt
c
b
a
$ sort foo.txt
a
b
c

sort允許多個文件作爲其參數,可以將多個文件融合成一個已經排序的整體文件。

$ sort file1.txt file2.txt file3.txt > final_sorted_list.txt

以上將三個文本文件拼接成一個已經排序好的整體文件.
表1 常見的sort選項

選項 全局選項表示 描述
-b –ignore-leading-blanks 默認情況下,整個行都會進行排序操作,也就是從行的第一個字符開始.添加該選項後,sort會忽略行開頭的空格,並且從第一個非空白字符開始排序.
-f –ignore-case 排序時不區分大小寫
-n –numeric-sort 基於字符串的長度進行排序.該選項使文件按數值順序而不是按字母表順序進行排序.
-r –reverse 逆序排序
-k –key=field1[,filed2] 對field1與field2之間的字符排序,而不是整個文本行.
-m –merge 一個排好序的文件,而不執行額外的排序操作
-o –output=file 將排序結果輸出到文件而不是標準輸出
-t –field-separator=char 定義字段分隔符.默認情況下,字段是由空格或製表符分開的

作爲例子,我們給出使用du命令+sort命令輸出home目錄下前10個文件或目錄佔用空間最大的文件.

$ du -sh ~/* | head
16K     /home/lmj/6.15
19G     /home/lmj/anaconda3
13M     /home/lmj/anything
29M     /home/lmj/apex
16K     /home/lmj/bak.bashrc.swp
19M     /home/lmj/cocoapi
27M     /home/lmj/code_faster
349M    /home/lmj/code_tx2
809M    /home/lmj/crawler
307M    /home/lmj/data

我們可以使用sort -n選項,對其所有空間佔用進行排序,這裏使用了-r進行了逆序排序,即從大到小.

$ du -sh ~/* | sort -nr | head
809M    /home/lmj/crawler
445M    /home/lmj/trt_maskrcnn
412K    /home/lmj/sampleUffMaskRCNN
396K    /home/lmj/face_detect_demo
349M    /home/lmj/code_tx2
313M    /home/lmj/DeepFashion
307M    /home/lmj/data
225M    /home/lmj/log
199M    /home/lmj/ubuntu18
172K    /home/lmj/sampleFasterRCNN

但是這種排序僅僅對數值出現在第一行的開頭有效.如果使用ls -l命令呢?

$ ls -l ~/ | head
total 48112
total 48112
drwxrwxr-x  2 lmj lmj     4096 Jun 15 14:06 6.15
drwxrwxr-x 26 lmj lmj     4096 Apr 22 12:17 anaconda3
drwxrwxr-x  2 lmj lmj     4096 Feb 25 15:16 anything
drwxrwxr-x 11 lmj lmj     4096 Sep 25  2019 apex
-rw-r--r--  1 lmj lmj    16384 Apr  3 10:01 bak.bashrc.swp
drwxrwxr-x  8 lmj lmj     4096 Dec  4  2019 cocoapi
drwxrwxrwx 10 lmj lmj     4096 Dec  7  2019 code_faster
drwxrwxr-x 10 lmj lmj     4096 May  3 15:37 code_tx2
drwxrwxr-x  5 lmj lmj     4096 Apr 14  2019 crawler

此時,可以用-k選項

$ ls -l ~/ | sort -nr -k 5| head

3. uniq–通知或省略重複的行

給定一個已經排序好的文件(包括標準輸入)後,uniq會刪除任何重複的行並將結果輸出到標準輸出中.它通常用sort結合以刪除sort輸出內容出重複的行.
簡單的例子

$ cat > foo.txt
a
b
c
a
b
c

因爲uniq 只對排好序的文本纔有作用,因此直接使用沒有任何效果.

$ sort foo.txt | uniq
a
b
c

表2 常見的uniq選項

選項 功能描述
-c 輸出重複列表,並且重複行前面加上其出現次數
-d 只輸出重複行,但不包括單獨行
-f n 忽略每行前n個字段
-i 行與行之間比較時忽略大小寫
-s n 跳過每行的前n個字符
-u 僅輸出不重複的行,爲默認選項

例如

$ sort foo.txt | uniq -c
      2 a
      2 b
      2 c

4. cut—刪除文本行中部分內容

cut命令用於從文本行中提取一段文字並將其輸出至標準輸出。
表3 cut選擇選項

選項 功能描述
-c char_list 從文本行中提取char_list定義的部分內容
-f field_list 從文本行中提取field_list定義的一個或多個字段
-d delim_char 指定-f選項後,使用delim_char作爲字段分界符號,默認爲單個Tab製表符
–complement 從文本中提取整行,除了那些由-c和/或-f指定的部分

簡單的例子

$ cut -f 3 foo.txt

用於切出foo.txt中每行以製表符爲分隔符的第三個字段.
例如此時我們切割出的格式爲

06/01/2006
10/30/2008
03/20/2006

進一步我們可以把年份切割出來

$ cut -f 3 foo.txt | cut -c 7-10

因爲固定第7-10個字符表示的是年份.
以下例子展示指定費Tab字符爲製表符,從/etc/passwd文件中提取每行的第一個字符

$ cut -d ":" -f 1 /etc/passwd | head
root
daemon
bin
sys
sync
games
man
lp
mail
news

5. paste—合併文本行

pastecut逆操作.它向文件中增加一個或是更多的文本列.該命令讀取多個文件並將每個文件中提取出的字段結合爲一個整體的標準輸出流.
例如對於兩個行數相同,且信息對應的文件 distros-dates.txt和distros-versions.txt,可以使用paste將各個參數按照指定順序進行排列.

$ paste distros-dates.txt distros-versions.txt

6. join—連接兩個文件中具有相同字段的行

joinpaste相似,都是向文件添加列信息.不同的是,其通常與“關聯數據庫”聯繫在一起,它是一個基於共享數據庫中把共享關鍵字段多個表格的數據組合成一個期望結果。
命令使用與patse類似,例如對於兩個存在首列共享字段的文件,且按照關鍵字段排好序,則可以使用

$ join distros-dates.txt distros-versions.txt

7. comm–逐行比較兩個已排序文件

comm命令一般用於文本文件之間的比較,顯示兩文件中相異的行以及相同的行.
首先,產生兩個相近的文件

$ cat > file1.txt
a
b
c
d
$ cat > file2.txt
b
c
d
e

使用comm比較文件差異

$ comm file1.txt file2.txt
a
                b
                c
                d
        e

comm輸出三列內容,第一列顯示第一個文件獨有的行,第二列顯示第二個文件獨有的行,第三列顯示兩個文件共有的行。
comm還支持-n參數,可以省略輸出第n列的內容.

8. diff—逐行比較文件

diff功能與comm類似,但是更復雜,支持多種輸出格式,並且具備一次性處理大文件集的能力。diff通常被軟件開發者用於檢查不同版本的源代碼之間的差異,因爲其能遞歸檢查源代碼目錄(通常稱爲源樹).diff常見用法就是創建diff文件和布丁。

$ diff file1.txt file2.txt
1d0
< a
4a4
> e

默認形式的輸出結果實際上是對兩者文件差異的一個簡潔描述.每一組改動的前面都有一個以“範圍 執行操作 範圍”形式(range operation range)表示的改變操作命令,該命令會告訴程序對第一個文件的某個位置進行某種改變,便可實現與第二個文件內容一致.diff改變命令如下表.
表20-4 diff改變命令

改變操作 功能描述
r1ar2 將第二個文件中r2位置的行添加到第一個文件中的位置r1處
r1cr2 用第二個文件r2處的行代替第一個文件r1處的行
r1dr2 刪除第一個文件r1處的行,並且刪除的內容作爲第二個文件r2行範圍的內容

默認格式並沒有其它格式的應用廣泛,上下文格式統一格式纔是比較常用的格式.
上下文格式的輸出結果

$diff -c file1.txt file2.txt
*** file1.txt   2020-06-22 11:20:05.940633105 +0800
--- file2.txt   2020-06-22 11:20:19.641086025 +0800
***************
*** 1,4 ****
- a
  b
  c
  d
--- 1,4 ----
  b
  c
  d
+ e

該結果以兩個文件的名字和時間信息爲開頭,第一個文件用星號表示,第二個文件用破折號表示.輸出結果的其餘部分出現的星號和破折號則分別表示各自所代表的文件.其它內容便是兩個文件之間的差異組,包括文件的默認行號.第一組差異,以*** 1,4 ****開頭,表示一個文件的第1行到第4行;第二組便以--- 1,4 ----,表示第二個文件的第1行到第4行,每個差異行都是以如下四個標識符之一開頭.
表5 diff上下文格式差異標識符

標識符 含義
(無) 該行表示上下文文本,表示兩個文件共有的行
- 缺少的行,表示該行僅在第一個文件中出現,第二個文件中則沒有
+ 多餘的行,表示該行僅在第二個文件中出現,第一個文件中沒有
! 改變的行.兩個版本的行內容都會顯示出來,每一個都各自出現在差異組中相應部分

統一格式與上下文格式相似但是更簡明,此格式用-u選項指定.

$ diff -u file1.txt file2.txt
--- file1.txt   2020-06-22 11:20:05.940633105 +0800
+++ file2.txt   2020-06-22 11:20:19.641086025 +0800
@@ -1,4 +1,4 @@
-a
 b
 c
 d
+e

統一格式與上下文格式最顯著的區別是,統一格式沒有重複的文本行.@@ -1,4 +1,4 @@字符串表示差異組描述的兩個文件各自的行範圍.之後每一行都以下面三種可能的標識符開頭.
表6 diff統一格式的差異標識符

字符 含義
(無) 兩個文件共有的行
- 相對於第二個文件而言,,第一個文件中沒有的行
+ 第一個文件多餘的行

9. patch—對原文件進行diff操作

patch命令用於更新文本文件.它利用diff命令的輸出結果將較舊版本的文件升級成較新版本.例如在Linux內核幾百萬行的代碼中,每個開發者僅負責小部分,對每位開發者而言,每對代碼改動一次就得向其他開發者發送整個內核源代碼不切實際,實際上,一般只要發送diff補丁文件即可.diff/path主要有如下優點

  • 與源代碼樹大小相比,diff文件很小
  • diff文件非常簡潔地描述了文件所做的改變,便於補丁的接收者快速對其評價
    生成供patch使用的diff文件,GNU文件系統建議採用如下方式:
diff -Naur old_file new_file > diff_file

此處old_file既可以是單獨的文件也可以是包含文件的目錄,使用-r參數是爲了進行遞歸目錄樹搜索.
一旦創建了diff文件,便可以將其用於修補原文件old_file,從而升級爲新文件new_file.

$ diff -Naur file1.txt file2.txt > patchfile.txt
$ patch < patchfile.txt
patching file file1.txt
$ cat file1.txt
b
c
d
e

10.tr—替換或刪除字符(非交互式)

之前描述的文本編輯大多是交互式的,也就是說只要手動移動鼠標然後輸入需要進行的改變.然而,也可以進行非交互的方式進行文本編輯.
tr是替換字符命令,可以將其看做基於字符的查找和替換操作.
下例是使用tr進行大小寫字母替換的例子

$ echo "lowercase letters" | tr a-z A-Z
LOWERCASE LETTERS

也就是說,tr可以對標準輸入進行操作並且將結果以標準形式輸出.tr有兩個參數:等待轉換的字符集和與之對應的替換字符集.字符集的表示方式有

  • 枚舉列表:例如,ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • 字符範圍:例如,A-Z
  • POSIX字符類:例如[:upper:].

多數情況下,兩個字符集應該是同等長度;然而,第一個字符集比第二個字符集長也是有可能的,例如

$ echo "lowercase letters" | tr [:lower:] A
AAAAAAAAA AAAAAAA

tr還有個有趣的用法,使用-s選項,可以“擠兌”(刪除)重複出現的字符,示例如下

$ $ echo "aabbcc" | tr -s ab
abcc

請注意,重複的字符必須是毗鄰的,否則不起作用

11. sed—用於文本過濾和轉換的流編輯器

sed是stream editor(流式編輯器)的縮寫,它可以對文本流、指定文件集或標準輸入進行文本編輯.
sed的用法,總的來說,首先給定sed某個簡單的編輯命令(在文本行中)或是包含多個命令的腳本文件名,然後sed便對文本流的內容執行給定的編輯命令.例如

$ echo "front" | sed "s/front/back/"
back

首先echo生成了只包含一個單詞的文本流,然後將該文本流叫給sed處理,而sed對其執行s/front/back/指令,最後輸出"back".可以認爲這裏sed與vi中的替換命令相似.
sed的命令以單個字母開頭,上個例子中,以字母s表示替代,氣候緊跟替換字符,替換字符由分界符的斜線字符分開.分界符選擇任意,習慣上使用斜線.
sed中國的多數命令允許在其前添加一個地址,該地址用來指定輸入流的哪一行被編輯.如果地址省略,則默認對第一行編輯.最簡單的地址就是行號.

$ echo "front" | sed "1s/front/back/"
back

表7 sed地址表示法

地址 功能說明
N n是正整數表示行號
$ 最後一行
/regexp/ 用POSIX基本表達式描述的行
addr1,addr2 行範圍,從addr1至addr2的所有行
first~step 代表從行號爲first開始,以step爲間隔的所有行.例如1~2爲所有奇數行
addr1,+n addr1行及其之後的n行
addr! 除了addr行之外的所有行,addr可以是以上任意表示形式

例如

$ sed -n '1,5p' distros.txt

p命令代表輸出指定行,這裏輸出了第1行到第5行,-n選項是不會自動打印選項,以防sed會默認輸出每一行內容.

$ sed -n '/SUSE/p' distros.txt

以上是使用正則表達式搜索匹配道SUSE的行.
我們已經學了s和p選項,sed更完整的基本編輯指令如下
表8 sed基本編輯指令表

命令 功能描述
= 輸出當前行號
a 在當前行後附加文本
d 刪除當前行
i 在當前行前輸入文本
p 打印當前行.默認情況下,sed會輸出每一行並且只編輯文件內那些匹配指定地址的行,使用-n選項後,默認操作被覆蓋.
q 退出sed不再處理其他行,如果沒有指定-n選項,就會輸出當前行
Q 直接退出sed不再處理行
s/regexp/replacement/ 將regexp的內容替換爲replacement代表的內容
y/set1/set2 將字符集set1轉換爲字符集set2,與tr不同,sed要求這兩個字符集等長.

12 aspell—交互式拼寫檢查工具

檢查一篇簡單散文的拼寫錯誤,可以用如下方式

aspell check textfile

其檢驗模式是與用戶交互的,被懷疑的錯誤字符以高亮顯示,0~9顯示拼寫建議,還有一些其它操作.
首先,創建含拼寫錯誤的txt,然後檢查它

$ cat > foo.txt
The quick brown jimped over the laxy dog
$ aspell check foo.txt
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章