Linux.Shell編程筆記-基本文本處理

來源:互聯網
上載者:User

第五章 基本文本處理排序文本

文本處理是UNIX/LINUXShell編程中幾乎最重要的一部分。在UNIX/LINUX 的設計中,一切都是檔案,而系統中許多程式的協同工作是通過文木或者文字資料流來實現的。因此,UNIX/LINUX 中的文本處理以及文字資料流的設計就成了重要的環節.

管道是UNIX/LINUX中的一個重要發明,管道串連了各種處理工具,組建文字資料流。在UNIX/LINUX 中,文本處理工具常常被設計成過濾器的形式。通過管道串連不同過濾器,這樣,很簡單的拼接就能實現需求的功能。

Sort命令的行排序

許多資料(文本)檔案都按照一定的格式組織,這些文木檔案以可一讀的方式提供資訊檢索和處理。一般來說,這種有格式的文字檔都可以排序。排序後的文木檔案更利於檢索。

常見的排序演算法很多,例如胃泡排序、歸併排序、快速排序等,化是排序效率各不相同。

UNIX/LINUX下提供的排序工具sort可以生產力,並且,通常情況下,它比你寫的排序演算法高效很多。因此,即使不瞭解排序的具體實現細節,你也一可以放心人膽地使用sort排序。

sort命令將輸入看成是具有多條記錄的資料流,而記錄由欄位組成,記錄是以分行符號為界定符號,每行對應於一條記錄。欄位則是以空白字元為界定,sort命令一也提供使用者指定欄位界定字元的參數。

在未提供參數的情況下,sort命令會根據當前字元集(locale )所定義的次序排序。例如,在傳統的C looal。中,sort命令會按照ASCII順序排序,如果需要改變定序,可以修改當前字元集。

[houchangren@ebsdi-23260-oozie data]$ catfruits.txt   //查看檔案內容apple%%banaebananaapplePresimmonBananaorangepresimmon[houchangren@ebsdi-23260-oozie data]$ sortfruits.txt   //預設排序appleapple%%banaebananaBananaorangepresimmonPresimmon[houchangren@ebsdi-23260-oozie data]$ echo$LANG  //查看預設設定字元集zh_CN.UTF-8[houchangren@ebsdi-23260-oozie data]$LANG=EN_US sort fruits.txt  //設定成EN_Us的排序%%banaeBananaPresimmonappleapplebananaorangepresimmon

-d參數 是按照字典排序(預設)

-f 是排序前都按照都寫來排序(小寫全轉成大寫)

 [houchangren@ebsdi-23260-oozie data]$ sort -d-f fruits.txt    appleapple%%banaebananaBananaorangepresimmonPresimmon

-u 去重複,相同行去掉

[houchangren@ebsdi-23260-oozie data]$ sort-d -f -u fruits.txtapple%%banaebananaorangePresimmon
Sort命令的欄位排序

sort命令還可以對欄位進行排序。在sort的參數列表中,-k參數可以選定排序欄位,而-t參數可以選擇欄位分界符,如果沒有設定,則預設是空白字元。

[houchangren@ebsdi-23260-oozie data]$ cat sort.txtkeyDataXSZKCZY:XXXSCK:604834:AFS:3636351      d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:604836:AFS:3636353      d_20131220170748-1600299142     3keyData XSZKCZY:XXXSCK:604838:AFS:3636355       d_20131220170748-1600299142     1keyDataXSZKCZY:XXXSCK:605180:AFS:3639304      d_20131220170748-1600299142     6keyDataXSZKCZY:XXXSCK:606728:AFS:3658757      d_20131220170748-1600299142     5keyDataXSZKCZY:XXXSCK:607072:AFS:3661194       d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:607188:AFS:3661453      d_20131220170748-1600299142     23keyDataXSZKCZY:XXXSCK:607195:AFS:3661460      d_20131220170748-1600299142     4keyDataXSZKCZY:XXXSCK:607197:AFS:3661462      d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:607199:AFS:3661464      d_20131220170748-1600299142     2[houchangren@ebsdi-23260-oozie data]$ sort -t $'\t' -k4 sort.txt    //因為\t比較特殊所以要用$keyDataXSZKCZY:XXXSCK:604838:AFS:3636355      d_20131220170748-1600299142     1keyDataXSZKCZY:XXXSCK:604834:AFS:3636351      d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:607072:AFS:3661194      d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:607197:AFS:3661462      d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:607199:AFS:3661464      d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:607188:AFS:3661453      d_20131220170748-1600299142     23keyDataXSZKCZY:XXXSCK:604836:AFS:3636353      d_20131220170748-1600299142     3keyDataXSZKCZY:XXXSCK:607195:AFS:3661460      d_20131220170748-1600299142     4keyDataXSZKCZY:XXXSCK:606728:AFS:3658757      d_20131220170748-1600299142     5keyDataXSZKCZY:XXXSCK:605180:AFS:3639304      d_20131220170748-1600299142     6 [houchangren@ebsdi-23260-oozie data]$ sort -t $'\t' -k4 -n sort.txt   keyDataXSZKCZY:XXXSCK:604838:AFS:3636355      d_20131220170748-1600299142     1keyDataXSZKCZY:XXXSCK:604834:AFS:3636351      d_20131220170748-1600299142     2keyData XSZKCZY:XXXSCK:607072:AFS:3661194       d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:607197:AFS:3661462      d_20131220170748-1600299142     2keyDataXSZKCZY:XXXSCK:607199:AFS:3661464      d_20131220170748-1600299142     2keyData XSZKCZY:XXXSCK:604836:AFS:3636353       d_20131220170748-1600299142     3keyDataXSZKCZY:XXXSCK:607195:AFS:3661460      d_20131220170748-1600299142     4keyDataXSZKCZY:XXXSCK:606728:AFS:3658757      d_20131220170748-1600299142     5keyData XSZKCZY:XXXSCK:605180:AFS:3639304       d_20131220170748-1600299142     6keyDataXSZKCZY:XXXSCK:607188:AFS:3661453      d_20131220170748-1600299142     23

-n參數讓sort命令按照整數數字進行比較。之前的排序很好的說明了,23在中間

Sort 小結

sort是一個重要的命令,你可以在許多重要的UNIX/LINUX shell中見到它的身影:只要有資料存在,並有檢索的需求,往往就有sort的支援。如果給UNIX/LINUX的命令論資排輩,sort絕對可以進入前十名。

上邊所做的只是sort命令冰山一角,sort命令的強大之處遠不止於此。除了對文本

行和欄位進行排序,sort命令和其他命令結合使用〔它本身就被設計成過濾器的模式)將實現強大的功能,例如,可以對文字區塊進行排序處理等.

並且,sort命令的效率是值得稱道的:自從它問世起,已經有許多人對它進行研究、最佳化和調整。它肯定比你寫的排序演算法工作得更好,相信它,而不要嘗試去重複發明輪子〔編寫冗餘的脆弱的排序演算法)。

但是,注意,sort命令是不穩定的口排序演算法的穩定性指的是:兩條相同的記錄輸入順序和輸出順序保持不變。

排序欄位都相同,但是輸出和輸入的順序卻不一致。所以sort不是穩定的排序實現。GUN的coreutils包中的sort命令彌補了這個不足。現在。你可以通過一stable選項來使輸入輸出的相同記錄順序不變了。但是,這個參數相應會降低sort命令的效率(採用稍微低效的排序演算法來獲得穩定性).

當sort作為過濾器在管道中使用時,排序演算法的穩定性就變得重要了。因此,你需要根據穩定性(stable )是否對自己的命令重要,來決定是否採用--stable參數。

文本去重

由於 sort -u去重複的命令只是對指定排序的列相同就會去重,但是可能其他欄位不同,所以有時候可能不是我們想要的。

UlSIX\Linux系統中有另一條命令用於資料一記錄去重,它足uniq.uniq命令會去除資料流中重複的記錄,只留下第一條記錄.它常常被用於管道中,例如,接在sort命令之後用於去重。

uniq命令主要有3個選項,-c 用於顯示出現重複行的計數,-d選項僅顯示重複行,-u選項僅顯示不重複的行

[houchangren@ebsdi-23260-ooziedata]$ cat fruit.txt%%banae banana  applePresimmon%%banae apple Banana  orange  presimmon[houchangren@ebsdi-23260-ooziedata]$ sort fruit.txt | uniq -c     //這個地方兩個apple因為後邊的空格導致認為是兩個記錄      1 apple      1 apple       2 %%banae       1 banana        1 Banana        1 orange        1 presimmon      1 Presimmon[houchangren@ebsdi-23260-ooziedata]$ sort fruit.txt | uniq -c -d  //僅顯示重複行      2 %%banae [houchangren@ebsdi-23260-ooziedata]$ sort fruit.txt | uniq -c -u    //僅顯示不重複行      1 apple      1 apple       1 banana        1 Banana        1 orange        1 presimmon      1 Presimmon[houchangren@ebsdi-23260-ooziedata]$
統計文本行數、字數以及字元數

Unix/linux中的wc命令可以提供文本的行數、字數、字元數統計。wc命令也是POSIX中標準的一部分,你可以放心大膽地使用。

-c 參數含義是讓WC命令顯示字元的個數。

-w 參數含義是讓WC命令顯示單詞的個數。

-l 參數含義是讓WC命令文本行的行的個數。

[houchangren@ebsdi-23260-oozie data]$ wc/etc/passwd 61   92 2867 /etc/passwd[houchangren@ebsdi-23260-oozie data]$ wc -c/etc/passwd2867 /etc/passwd[houchangren@ebsdi-23260-oozie data]$ wc -c-w /etc/passwd  922867 /etc/passwd[houchangren@ebsdi-23260-oozie data]$ wc -c-w -l /etc/passwd 61   92 2867 /etc/passwd[houchangren@ebsdi-23260-oozie data]$

//尋找上層目錄中name是.sh結尾的個數

[houchangren@ebsdi-23260-oozie data]$ find../ -iname "*.sh" |wc -l11 

//找出/etc/passwd檔案中包含bash字串的行的個數。一般來說,就是系統中啟動

shell為bash的使用者的個數。

[houchangren@ebsdi-23260-oozie data]$ grepbash /etc/passwd | wc -l25

//用純grep達同樣效果

[houchangren@ebsdi-23260-oozie data]$ grep-c bash /etc/passwd25 

// WC命令統計目前的目錄下所有以.sh結尾的檔案,統計它們中的字元數、單詞數和行

數,並且在最一行將總計的結果列印出來。

[houchangren@ebsdi-23260-oozie shell]$ wc*.sh  6    7   51 add.sh 19   29  337 a.sh  7   16   85 checkUserIsExist.sh  8   11   55 if.sh 16   58  284 testalg.sh  8   20  206 testcase.sh   6   7   42 testfor.sh 26   51  319 testwhile.sh 11   27  132 user_login.sh 15   26  193 whileexample2.sh 17   38  253 whileexample.sh 139  2901957 總計

Note

Wc命令的執行會隨著locale的設定有不同的結果。因為不同的locale會影響Wc命令解釋位元組序列時的字元/單詞分隔器。

列印和格式化輸出

Linux下列印和格式化文本的工具很多,例如pr, fmt, fold等。它們各有不同的用途。

使用pr列印檔案

UNIX/Linux的 pr命令可以用來將文本轉換成適合列印的檔案。這個工具的一個基本用途就是將較大的檔案分割成多個頁面,並為每個頁面添加標題。  

  比如,pr可以將一個150行文本的檔案轉換成三個文本頁,然後讓使用者進行列印。

  在預設情況下,每個頁面會包含66行文本,不過通過pr的-l參數,使用者可以改變這一規則。  

  可以用來控制文本輸出效果的參數很多,一般來說,每頁的標題就是這個文檔的檔案名稱。當然,使用者也可以自行定義標題,比如:

  $ pr -h "My report" file.txt

  如果不使用上面的-h參數,列印的頁面會用“file.txt”作為標題,而加上-h參數後,頁面會使用該參數後指定的“My report”作為標題。

  使用者還可以使用pr命令將文本分列列印。這對於語句短小的文本來說比較有用,如果語句比較長,pr會在適當的位置進行換行。比如,要將file.txt檔案按兩列列印,可以使用以下命令:

  $ pr -2 -h "My report" file.txt  

  預設情況下,pr會為每個頁面加入分行符號(比如空行),不過使用者也可以使用定位字元來代替空行。可以下面這段命令使定位字元來代替空行:

  $ pr -f file.txt  

  如果使用者只是想列印檔案,而不想儲存它,那麼這個功能比較合適,但是如果使用者同時也要儲存檔案,那麼添加的定位字元會讓檔案看起來比較亂。

  需要記住的是,pr是一個標準的輸出工具,可以直接輸出到印表機,如果你希望將結果儲存在檔案中,則需要重新導向它的輸出,如下面這個例子:

$ pr file.txt>file.output

測試執行個體:

[houchangren@ebsdi-23260-ooziedata]$ pr -f  fruit.txt2014-01-1810:56                    fruit.txt                     Page 1%%banae banana  applePresimmon%%banae apple Banana  orange  presimmon[houchangren@ebsdi-23260-ooziedata]$ pr -f -c1  fruit.txt2014-01-1810:56                    fruit.txt                     Page 1%%banae banana  applePresimmon%%banae apple Banana  orange  presimmon[houchangren@ebsdi-23260-ooziedata]$ pr -f -c1 -h "test" fruit.txt2014-01-18 10:56                       test                       Page 1%%banae banana  applePresimmon%%banae apple Banana  orange  presimmon[houchangren@ebsdi-23260-ooziedata]$ pr -f -c1 -t fruit.txt%%banae banana  applePresimmon%%banae apple Banana  orange  presimmon

在pr命令中 –c 參數是顯示多少欄, -t 參數表示不顯示標題

NOTE

在pr命令裡,直接使用-10的效果和使用-c10是一樣的‘這是因為pr有一個參數是-Column,這個參數即直接在連字號後面接數字,表示輸出的欄數.

使用fmt命令格式化文本

除了pr命令,UNIX/Linux下還有一條fmt命令可以格式化文本段落,使文本不要超出可見的螢幕範圍口fmt指令會從指定的檔案裡讀取內容,將其依照指定格式重新編排後,輸出到標準輸出裝置。若指定的檔案名稱為“一”,則fmt指令會從標準輸入裝置讀取資料口

-w 參數告訴fmt命令每行的最大字元數。

-s參數告訴fmt命令只拆開字數超出每列字元數的列,但不合并字數不足每列字元數的列

NOTE

警告,無論是pr還是fmt,在不同版本系統中的行為都不盡相同。因此你需要在不同版本的系統上

通過查閱manpage,來確定格式化輸出工具的功能。

使用fold限制文本寬度

LINIXILinux的fold指令會從指定的文什裡讀取內容,將超過限定列寬的列加入增列字元

後,輸出到標準輸出裝置。若不指定任何檔案名稱,或是所給予的檔案名稱為”-“,則fold指令會從標準輸入裝置讀取資料。

Note

注意了,fold的-w參數和fmt的-w參數並不相同。fold的-w參數很生硬地將文本輸出行截斷,但是並不判斷是否單詞也被截斷。而fmt的-w.參數會判斷單詞是否能夠正常顯示〔不被截斷顯示),遇到無法正常顯示的,fmt會將該單詞整體移到下一行,而fold會將之攔腰截斷。

提取文本開頭和結尾

//查看tomcat前20行日誌

Head 查看檔案的開頭

head -n 指定行

[root@ebsdi-23260-oozie logs]# head -20  catalina.out

tail命令查看檔案的結尾

tail –n 指定行

[root@ebsdi-23260-oozie logs]# tail  -20 catalina.out    

-f參數動態查看

[root@ebsdi-23260-oozie logs]# tail -f catalina.out
欄位處理Cut取文本中的某個欄位

-d參數規定了cut命令接受的欄位分隔符號。

-f參數規定了cut命令擷取的欄位列,後邊跟數字多個用逗點隔開。

[houchangren@ebsdi-23260-oozie data]$ cut-d  ':' -f 1,7 /etc/passwd | grep bash |head -10root:/bin/bashmapred:/bin/bashhdfs:/bin/bashwangjuntao:/bin/bashyangzhi:/bin/bashhuanghu:/bin/bashzhangguochen:/bin/bashhouchangren:/bin/bashhadoop:/bin/bashneil:/bin/bash
join 串連欄位

Linux一下的join命令可以串連不同的檔案,使得具有相同key值的記錄資訊連到一起。它會根據指定欄位,找到兩個檔案中指定欄位內容相同的行,將它們合并,並根據要求的格式輸出內容。該命令對於比較兩個檔案的內容很有協助。

[houchangren@ebsdi-23260-oozie data]$ catstuff.txt1      zhangsan2       lisi3      wangwu6      maliu[houchangren@ebsdi-23260-oozie data]$ catsalary.txt1      10002      20003      23505      2400[houchangren@ebsdi-23260-oozie data]$ joinstuff.txt salary.txt1 zhangsan 10002 lisi 20003 wangwu 2350[houchangren@ebsdi-23260-oozie data]$ joinstuff.txt salary.txt  -a11 zhangsan 10002 lisi 20003 wangwu 23506 maliu[houchangren@ebsdi-23260-oozie data]$ joinstuff.txt salary.txt  -a21 zhangsan 10002 lisi 20003 wangwu 23505 2400
其他欄位處理方法

Awk,後邊會專有章節介紹

文本替換

UNIX\Linux下的文本替換有很多種實現方法,例如,可以通過sed命令。如果在文字編輯器

中,則有更多的選擇。但是,最簡單的命令還是tr.

使用tr替換字元

tr命令從標準輸入刪除或替換字元,並將結果寫入標準輸出。在命令需要小範圍內做文本替換時,tr命令非常有用。

tr命令格式

a.      tr str1 str2b.      tr {-d|-s} str1

tr完成的操作

a. 轉換字元
如果str 1和str2兩者都已指定,但-d標誌沒有指定,tr命令就會從標準輸入中將str1中所包含的每一個字元都替換成str2中相同位置上的字元。

b. 使用-d標誌刪除字元
如果-d標誌已經指定,tr命令就會從標準輸入中刪除str1中包含的每一個字元。

c. 使用-s標誌除去序列

如果-s標誌已經指定,tr命令就會除去包含在str1或str2中的任何字串系列中的除

第一個字元以外的所有字元。對於包含在str1中的每一個字元,tr命令會從標準輸出中除去除第一個出現的字元以外的所有字元。對於包含在str2中的每一個字元,tr命令除去標準輸出的字元序列中除第一個出現的字元以外的所有字元。

[houchangren@ebsdi-23260-oozie data]$ cat fruit.txt%%banae banana  applePresimmon%%banae apple Banana  orange  presimmon[houchangren@ebsdi-23260-oozie data]$ tr'a-z' 'A-Z' < fruit.txt > fruit.txt.upper[houchangren@ebsdi-23260-oozie data]$ catfruit.txt.upper%%BANAE BANANA  APPLEPRESIMMON%%BANAE APPLE BANANA  ORANGE  PRESIMMON[houchangren@ebsdi-23260-oozie data]$ catfruit.txt | tr -d 'a' > fruit.txt.rm[houchangren@ebsdi-23260-oozie data]$ catfruit.txt.rm%%bne bnn  pplePresimmon%%bne pple Bnn  ornge  presimmon[houchangren@ebsdi-23260-oozie data]$ catfruit.txt.rm |tr -s '%%' '$$' > fruit.txt.rep[houchangren@ebsdi-23260-oozie data]$ catfruit.txt.rep$bne bnn  pplePresimmon$bne pple Bnn  ornge  persimmon
其他執行個體
#若要將大括弧轉換為小括弧,請輸入>>> tr '{}' '()' < textfile> newfile#若要將大括弧轉換成方括弧,請輸入:>>> tr '{}' '\[]' <textfile> newfile#若要建立一個檔案中的單字清單,請輸入;>>> tr -cs '[:lower:][:upper:]''[\n*]' <textfile > newfile#若要從某個檔案中刪除所有Null 字元,請輸入:>>> tr -d '\0' <textfile > newfile#若要用單獨的換行替換每一序列的一個或多個換行,清輸入>>> tr -s  '\n' < textfile >new file或者>>> tr -s '\012' <textfile >newfile#若要以“?”(問號)替換每個非列印字元〔有效控制字元除外),請輸入:>>> tr -c '[:print:][:cntrl:]''[?*]' <textfile > newfile#若要以單個“非”字元替換<space>字元類中的每個字元序列,請輸入:>>> tr -s '[:space:]' '[#*]'其他選擇

其實,tr的文本替換功能僅僅實現了最簡單的操作,如果有更複雜的需求,例如有條件判斷等邏輯的,就需要更強大和複雜的工具了。而這類工具,往往都可以稱之為語言。

Linux下常見的具有這類功能的工具有如下這些項。

perl強大的Regex文持在UNIX/linux世界無出其右,文木替換自然是小菜;

sed sed工具處理文字資料流,亦可以輕鬆地實現文木替換.

awk awk語言具有邏輯判斷與迴圈等特性支援,並且,在文本處理時根據需求,強大的可定製性也是其長盛不衰的原因。

python作為目前UNIX、Linux社區最流行的語言之一,python的文本處理模組相當強大,

亦可以完成幾乎你想要的替換功能。但是,python的執行效率比較慢,並且,使用python這麼龐大的語一言處理簡單的文本操作似乎有點大材小用.

一個稍微複雜的例子

需求:擷取一天中訪問最多的前100名

步驟:cut -> tr-> cut-> sort->uniq->sort->head

第一個欄位後是\t第二欄位後是空白符(多個)所以得截取了兩次

[houchangren@ebsdi-23260-oozie data]$ catips.txt 20:32  10.12.165.1     123872320:31  10.12.165.7     12392320:32  10.12.165.18    12832320:12  10.12.165.20    123462320:32  10.12.165.25    123244320:32  10.12.165.26    123243320:32  10.12.165.31    123452320:32  10.12.165.32    12320:32  10.12.165.33    1234520:32  10.12.165.33    12324520:32  10.12.165.36    12333320:32  10.12.165.37    12342320:32  10.12.165.38    1242320:32  10.12.165.39    1262320:32  10.12.165.40    1252320:32  10.12.165.255   1242320:32  224.0.0.2       1212320:32  224.0.0.22      1222320:32  224.0.0.251     1232220:32  224.0.0.252     12322[houchangren@ebsdi-23260-oozie data]$ cut-d $'\t' -f 2 ips.txt |tr -s '[" "]' $'\t'|cut -d $'\t' -f1|sort|uniq -c|sort -r|head -100     2 10.12.165.33     1 224.0.0.252     1 224.0.0.251     1 224.0.0.22     1 224.0.0.2     1 10.12.165.7     1 10.12.165.40     1 10.12.165.39     1 10.12.165.38     1 10.12.165.37     1 10.12.165.36     1 10.12.165.32     1 10.12.165.31     1 10.12.165.26     1 10.12.165.255     1 10.12.165.25     1 10.12.165.20     1 10.12.165.18     1 10.12.165.1     1

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.