IBM的LPI複習資料之LPI101-Topic103 :GNU和Unix命令(2)文字資料流和過濾器

來源:互聯網
上載者:User

引言:對於文本操作來說,除了剪下和粘貼外還有更多的操作,尤其是不使用GUI的時候,這更明顯。在本文中,作者講解了使用GUN文本工具包來進行文本處理。學完本文,你將會像專家一樣處理文本。

概述:本文介紹了“過濾器”,可以使用過濾器構建複雜的管道來處理文本。你將學會如何顯示文本、排序、單詞和行統計、轉換等多種操作技術。你還會學習使用sed編輯器。具體入下:

  • 通過向文本工具包過濾器發送文字檔或者輸出資料流來改變輸出;
  • 使用GNU文本工具包裡的命令列工具;
  • 使用sed指令碼來處理複雜的文本改變
本文針對的是LPIC-1的103.2目標,其權重為3.文本過濾文本過濾是這樣一個過程,接受輸入文字資料流,執行一些改變,然後轉寄給輸出資料流。儘管輸入輸出資料流可以來自檔案,在Linux和Unix環境中,過濾通常是通過構建一個命令列管道來實完成的。一個命令的輸出被重新導向給下一個命令作為輸入。管道和重新導向在另一篇文章中有詳細講解,現在我們看看管道和重新導向的操作符 | 和 >。流流就是一個可以使用庫函數讀寫的位元組序列,讀寫它的庫函數對上層應用程式屏蔽了底層裝置的細節。同一個程式可以使用流可以做到裝置無關的方式來讀取和寫入一個終端,一個檔案,或者網路通訊端。現代編程環境和shell都使用三個標準輸入輸出資料流:
  • stdin 標準輸入資料流,為命令提供輸入;
  • stdout 標準輸出資料流,用來顯示命令的輸出;
  • stderr 標準錯誤流,用來顯示命令的錯誤輸出
管道命令的輸入來自你提供的命令列參數,輸出顯示到你的終端裝置上。很多文本處理命令可以接收來自標準輸入資料流或者檔案的輸入。為了把一個命令的輸出作為另一個命令的輸入,你可以使用管道符號|。下面顯示了利用管道把echo 的輸出作為sort的輸入。
[root@localhost ~]# echo -e "apple\npear\nbanana" | sortapplebananapear[root@localhost ~]# 

每個命令都可能有選項或者參數。你同樣可以使用 | 來把第二個命令的輸出作為第三個命令的輸入,以此類推。通過構建長的命令管道(每個命令能力有限)來完成任務是Linux/Unix中常見的方法。 有時候,你可能會看到一個命令的參數是 - 而不是一個檔案名稱,這個-的含義是此命令的輸入來自標準輸入資料流而不是檔案。

輸出重新導向通過管道構建一個多個命令組成的流水線可以把結果輸出到終端上。但是有時候你會需要把結果儲存到檔案中。這可以通過輸出重新導向操作符>來完成。接下來我們將會使用一些小檔案,所以我們建立一個叫做 lpi103-2的檔案夾,然後cd到這個目錄下。然後我們使用>重新導向echo命令的輸出到一個叫做text1的檔案中。
[root@localhost ~]# mkdir lpi103-2[root@localhost ~]# cd lpi103-2/[root@localhost lpi103-2]# echo -e "1 apple\n2 pear\n3 banana" > text1
既然我們已經熟悉了管道和重新導向這兩個基本的工具,接下來我們看看一些常用的UNIX和LINUX文本處理命令和過濾器。本節只簡要介紹這些命令,具體的用法參考man手冊頁。Cat, od, split前面我們建立了text1檔案,現在我們來看看檔案裡是什麼。使用cat(concatenate的縮寫)命令來顯示一個文字檔的內容到標準輸出。
[root@localhost lpi103-2]# cat text1 1 apple2 pear3 banana

如果不給cat命令提供參數,那麼它將會把標準輸入資料流作為其輸入。這中特性和輸出重新導向配合就可以建立另一個檔案,如下:

cat >text29       plum3       banana10      apple

cat會持續地讀取標準輸入的內容直到到達檔案結尾。使用Ctrl + d來告訴cat標準輸入的結束。bash也是使用Ctrl+d來退出。本例使用Tan鍵來分割編號和水果名。注意,cat是concatenate的縮寫,是串連的意思。因為你可以使用cat來串連多個檔案一起輸出。下面,我們把text1,text2一起輸出顯示。

[root@localhost lpi103-2]# cat text*1 apple2 pear3 banana9plum3banana10apple

注意,上面兩個檔案輸出對齊的不同。要弄清楚其中的原因,你需要查看檔案裡的控制字元。控制字元用來控制輸出效果,本身並不顯示自身,所以我們需要以一種格式dump檔案來找出和解釋這些特殊的字元。GUN工具包裡的od命令可以完成這個任務。-A 選項指定字元位置的計數法,可以是x(十六進位),d(十進位),o(八進位)或者n(不顯示位置)。-t 用來指定顯示的方式,c是逸出字元的方式,a則是名字方式。

[root@localhost lpi103-2]# od text20000000 004471 066160 066565 031412 061011 067141 067141 0051410000020 030061 060411 070160 062554 0000120000031[root@localhost lpi103-2]# od -A d -t c text20000000   9  \t   p   l   u   m  \n   3  \t   b   a   n   a   n   a  \n0000016   1   0  \t   a   p   p   l   e  \n0000025[root@localhost lpi103-2]# od -A n -t a text2   9  ht   p   l   u   m  nl   3  ht   b   a   n   a   n   a  nl   1   0  ht   a   p   p   l   e  nl

我們的樣本檔案都很小,當遇到大檔案時就需要把它分割成多個小的分區。例如,你可能需要把一個大檔案分割成CD-大小的分區,這樣才能把它燒錄成CD盤。split命令用來完成分割任務,並且cat可以很容易地把分割的分區重新串連成原來的大檔案。預設情況下,split分割出的小檔案的檔案名稱格式為: xaa, xab,....。當然你可以通過命令列選項來改變預設值,也可以改變小檔案的大小以及是否按行分割或者按字元分割。看下面執行個體:

[root@localhost lpi103-2]# split -l 2 text1              # 按行分割,每2行一個檔案片
[root@localhost lpi103-2]# split -b 17 text2 y           # 按字元數分割,每個檔案片17個字元
[root@localhost lpi103-2]# cat yaa9plum3banana1[root@localhost lpi103-2]# cat y* x*9plum3banana10apple1 apple2 pear3 banana

注意yaa檔案片沒有以換行結束,所以輸出它以後,我們的bash提示符位移了。

wc, head, tailcat可以顯示檔案全部內容,這對於小檔案是合適的。但是駕駛你有一個大檔案,首先你可能需要使用wc(word count)來看看這個檔案有多大。wc命令用來顯示一個檔案有多少行、多少字元、多少位元組。ls -l命令也可以獲得檔案的位元組數。如下例:
[root@localhost lpi103-2]# ls -l text*-rw-r--r-- 1 root root 24 May  7 14:29 text1-rw-r--r-- 1 root root 25 May  7 14:48 text2[root@localhost lpi103-2]# wc text* 3  6 24 text1 3  6 25 text2 6 12 49 total

wc提供了其他的選項來控制輸出格式或者輸出其他的資訊,如最大行的長度,具體參看man手冊頁。

head和tail命令用來顯示一個檔案的首部和尾部。他們可以用作過濾器,也可以使用一個檔案名稱作為參數。預設情況下,head和tail都是顯示10行的內容。下面是個綜合的例子:
root@localhost lpi103-2]# dmesg | tail -n15 | head -n 6                          # 先從倒數15行開始到結束,然後是取前6行tg3 0000:02:00.0: eth0: Link is up at 100 Mbps, full duplextg3 0000:02:00.0: eth0: Flow control is on for TX and on for RXtg3 0000:02:00.0: eth0: Link is downtg3 0000:02:00.0: eth0: Link is up at 100 Mbps, full duplextg3 0000:02:00.0: eth0: Flow control is off for TX and off for RXBluetooth: Core ver 2.15

tail的另外一個常用的方式是 tail -f 檔案名稱。 當一個背景程式修改檔案時,可以通過這個命令追蹤檔案的變化,常用於記錄檔。Expand, unexpand, tr當我們建立text1和text2檔案時,我們在text2中使用了Tab字元。有時候你需要把tab換成空格,或者反之。expand和unexpand命令用來完成這個任務。兩個命令都提供了-t選項來設定Tab寬度。

[root@localhost lpi103-2]# expand -t 1 text2        # 把一個Tab替換成一個空格9 plum3 banana10 apple[root@localhost lpi103-2]# expand -t 8 text2 | unexpand -a -t2 | expand -t3  # 把一個Tab替換成8個空格,再把每2個空格替換成一個Tab, 在把每個Tab替換成3個空格9           plum3           banana10       apple
不幸的是,你無法使用unxpand把text1中的空格替換成Tab。因為unexpand至少需要2個空格才能換成Tab。不過,你可以使用tr命令來完成這種替換。因為tr就是一個單純的過濾器,你可以使用cat命令為其提供輸入。
[root@localhost lpi103-2]# cat text1 | tr ' ' '\t' | cat - text21apple2pear3banana9plum3banana10apple

如果想知道到底發生了怎樣的替換,可以使用od -ta來查看。

Pr, nl, fmtpr命令(print)被用來為列印而格式檔案。預設輸出的頭部包含檔案名稱、建立日期和時間、以及頁碼,尾部則是兩個空行。當操作多個檔案或者是標準輸入時,日期時間是現在的時間而不是那一個檔案的建立時間。nl命令(number lines)用來為行編號。cat -n 也可以用來編號。
[root@localhost lpi103-2]# nl text2 | pr -m - text1 | head2013-05-07 16:04                                                  Page 1     19plum    1 apple     23banana    2 pear     310apple    3 banana
另外一個用用的格式化文本的命令是fmt。它用來使用合適的邊距格式文本,可以用來串連多個短行為一行,也可以分割一個長行為多行。例子如下:
[ian@echidna lpi103-2]$ echo "This is a sentence. " !#:* !#:1->text3echo "This is a sentence. " "This is a sentence. " "This is a sentence. ">text3[ian@echidna lpi103-2]$ echo -e "This\nis\nanother\nsentence.">text4[ian@echidna lpi103-2]$ cat -et text3 text4This is a sentence.  This is a sentence.  This is a sentence. $This$is$another$sentence.$[ian@echidna lpi103-2]$ fmt -w 60 text3 text4This is a sentence.  This is a sentence.  This is asentence.This is another sentence.

sort, uniqsort命令對輸入的文本按照當前系統的定序進行排序後輸出。sort也可以用來合并已經排序好的檔案,以及檢查一個檔案是否已經排序。下面例子中,先把text1中的空格替換成Tab,然後再排序這兩個檔案。

[root@localhost lpi103-2]# cat text1 | tr ' ' '\t' | sort - text210apple1apple2pear3banana3banana9plum[root@localhost lpi103-2]# cat text1 | tr ' ' '\t' | sort -u -k1n -k2 - text21apple2pear3banana9plum10apple

請注意,10排到了最前面,因為預設是按照字母順序排序的。慶幸的是,sort支援數字和字母兩種排序方式,而且每一個列排序的方式還可以不同。預設各個列是根據Tab或者空格分隔的。

第二個例子中,第一列按照數字排序,第二列按照字母排序,-u則去除重複行。注意,我們仍然還有兩個apple行,這是因為唯一性測試是按照整行進行的。想想如何修改或者增加步驟來消除第二個apple行。另外一個命令uniq提供了另外一種控制重複行刪除的機制。uniq通常在排序好的基礎上進行操作,刪除連續的重複行。uniq還可以忽略某些欄位。如下:
[root@localhost lpi103-2]# cat text1 | tr ' ' '\t' | sort -k2 - text2 | uniq -f1    # 忽略第一個欄位
10apple3banana2pear9plum

cut, past, join現在我們來學習處理文本資料中欄位的三個命令。這三個命令在處理表格式資料的時候特別好用。第一個是cut, 它抽取檔案中的欄位。預設的欄位分割符是Tab。

[root@localhost lpi103-2]# cut -f1-2 --output-delimiter=' ' text2       # 抽取兩個欄位,並在輸出時欄位之間使用空格分開9 plum3 banana10 apple

paste命令用來把多個檔案中的相同行號的行對應串連起來,有點像pr命令的-m選項。

[root@localhost lpi103-2]# paste text1 text21 apple9plum2 pear3banana3 banana10apple

這隻是paste最簡單的用法,更多複雜的用法,請參考man手冊頁。

最後一個欄位操作命令是join。它通過一個匹配欄位來串連檔案(譯者註:類似於資料庫中表的等值串連)。串連的欄位必須是排序好的。
[root@localhost lpi103-2]# sort -k2 text2 | join -1 2 -2 2 text5 -apple 1 10banana 3 3

sedSed是stream editor。關於sed有很多文章和書籍來介紹。Sed超級強大,用它可以完成任何文本編輯工作。本文只是簡單介紹sed以吊起讀者的胃口,但是不會詳細介紹。與前面的所有文本處理命令一樣,sed也可以從檔案或者管道獲得輸入。其輸出則是標準輸出資料流。Sed讀取行到模式空間,對模式空間裡的內容進行編輯操作,然後把模式空間的內容寫到標準輸出。Sed可能會在模式空間組合多個行,也可能寫入檔案,唯寫選擇的輸出,或者根部不寫。Sed使用Regex來選擇操作的行,以及完成尋找和替換。一個保持緩衝區提供文本儲存的臨時空間。這個緩衝區可以替換模式空間,也可以被加入到模式空間,或者與模式空間進行交換。sed擁有一個有限的命令集合,這些命令與Regex以及保持緩衝區相結合將會帶來巨大的能力。一組sed命令的集合通常叫做sed指令碼。下面展示了三個簡單的sed指令碼。

[root@localhost lpi103-2]# sed 's/a/A/' text11 Apple2 peAr3 bAnana[root@localhost lpi103-2]# sed 's/a/A/g' text11 Apple2 peAr3 bAnAnA[root@localhost lpi103-2]# sed '2d;$s/a/A/g' text11 apple3 bAnAnA

第一個指令碼中,我們使用s(substitute)命令來把每一行的第一個a替換為A。第二個指令碼中,完成同樣的替換,只是會把每一行中所有的a都替換為A。第三個指令碼中,我們增加了d(刪除)命令,刪除第二行,然後把最後一行的a替換為A,兩個命令之間用;分割。sed預設是真多所有行進行操作,但也提供操作部分行的選項。這可以通過行號、Regex等表示。其中$表示最後一行。例子如下:

[root@localhost lpi103-2]# sed -e '2,${' -e 's/a/A/g' -e '}' text11 apple2 peAr3 bAnAnA[root@localhost lpi103-2]# sed -e '/pear/,/bana/{' -e  's/a/A/g' -e '}' text11 apple2 peAr3 bAnAnA[root@localhost lpi103-2]# sed -e '/pear/,/bana/{s/a/A/g}' text11 apple2 peAr3 bAnAnA

上面例子的作用是,把text1檔案中的最後兩行中的a替換成A。同時顯示了-e的作用是把多個命令串連起來。sed指令碼哈可以存放到檔案中。實際上你可能把經常用到的指令碼都存入檔案中。前面,我們使用tr命令把text1檔案中的空格替換為Tab。現在我們使用sed完成同樣的任務,並且把sed指令碼存入檔案中。

[root@localhost lpi103-2]# echo -e "s/ /\t/g">sedtab[root@localhost lpi103-2]# cat sedtab s/ //g[root@localhost lpi103-2]# sed -f sedtab text11apple2pear3banana

下面是最後一個Sed指令碼的例子:

[root@localhost lpi103-2]# sed '=' text219plum23banana310apple[root@localhost lpi103-2]# sed '=' text2 | sed 'N;s/\n//'19plum23banana310apple

本例中,我們使用了=命令,然後把輸出再交給sed來處理,來類比nl來給行進行編號。例子中,先使用=來列印行號,然後使用N命令把檔案下一行讀入模式空間,最後在模式空間中刪除兩行之間的分行符號。看起來不太好,因為行號和行內容之間沒有分割開。下面是改進版本:

[root@localhost lpi103-2]# cat text1 text2 text1 text2 >text6[root@localhost lpi103-2]# cat text61 apple2 pear3 banana9plum3banana10apple1 apple2 pear3 banana9plum3banana10apple[root@localhost lpi103-2]# ht=$(echo -en "\t")[root@localhost lpi103-2]# echo $ht[root@localhost lpi103-2]# sed '=' text6 | sed "N> s/^/      /> s/^.*\(......\)\n/\1$ht/"     11 apple     22 pear     33 banana     49plum     53banana     610apple     71 apple     82 pear     93 banana    109plum    113banana    1210apple

下面來具體分析各個步驟:

  1. 使用cat建立一個多行的檔案,備用
  2. 因為Tab鍵在bash中是自動補全快速鍵,不能直接輸入,所以建立一個bash變數儲存備用
  3. 使用=命令增加行號
  4. 讀入下一行到模式空間中
  5. 在行號前面增加6個空格
  6. 把分行符號前面的內容替換為最後六個字元(為了保證序號6位以內都能對齊),然後加上Tab。
Sed的第四個版本包含了Info格式的文檔,其中有大量精彩的例子,這在3.02版本中是沒有的。GNU sed可以使用--version選項來顯示當前的版本資訊。
[root@localhost lpi103-2]# sed --versionGNU sed version 4.2.1Copyright (C) 2009 Free Software Foundation, Inc.This is free software; see the source for copying conditions.  There is NOwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE,to the extent permitted by law.GNU sed home page: <http://www.gnu.org/software/sed/>.General help using GNU software: <http://www.gnu.org/gethelp/>.E-mail bug reports to: <bug-gnu-utils@gnu.org>.Be sure to include the word ``sed'' somewhere in the ``Subject:'' field.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.