初识sed和gawk
???????到目前為止, shell腳本最常見的一個(gè)用途就是處理文本文件。檢查日志文件、讀取配置文件、處理數(shù)據(jù)元素,shell腳本可以幫助我們將文本文件中各種數(shù)據(jù)的日常處理任務(wù)自動(dòng)化。但僅靠shell腳本命令來處理文本文件的內(nèi)容有點(diǎn)勉為其難。如果想在shell腳本中處理任何類型的數(shù)據(jù),你得熟悉Linux中的sed和gawk工具。這兩個(gè)工具能夠極大簡(jiǎn)化需要進(jìn)行的數(shù)據(jù)處理任務(wù)。
一.文本處理
 ???????有時(shí)候,你會(huì)發(fā)現(xiàn)需要自動(dòng)處理文本文件,可你又不想動(dòng)用全副武裝的交互式文本編輯器。在這種情況下,有個(gè)能夠輕松實(shí)現(xiàn)自動(dòng)格式化、插入、修改或刪除文本元素的簡(jiǎn)單命令行編輯器就方便多了。
 ???????Linux系統(tǒng)提供了兩個(gè)常見的具備上述功能的工具。本節(jié)將會(huì)介紹Linux世界中最廣泛使用的兩個(gè)命令行編輯器:sed和gawk。
1.sed編輯器
 ???????sed編輯器被稱作流編輯器(stream editor),和普通的交互式文本編輯器恰好相反。在交互式文本編輯器中(比如vim),你可以用鍵盤命令來交互式地插入、刪除或替換數(shù)據(jù)中的文本。流編輯器則會(huì)在編輯器處理數(shù)據(jù)之前基于預(yù)先提供的一組規(guī)則來編輯數(shù)據(jù)流。
 ???????sed編輯器可以根據(jù)命令來處理數(shù)據(jù)流中的數(shù)據(jù),這些命令要么從命令行中輸入,要么存儲(chǔ)在一個(gè)命令文本文件中。sed編輯器會(huì)執(zhí)行下列操作。
 ???????(1) 一次從輸入中讀取一行數(shù)據(jù)。
 ???????(2) 根據(jù)所提供的編輯器命令匹配數(shù)據(jù)。
 ???????(3) 按照命令修改流中的數(shù)據(jù)。
 ???????(4) 將新的數(shù)據(jù)輸出到STDOUT。
 ???????在流編輯器將所有命令與一行數(shù)據(jù)匹配完畢后,它會(huì)讀取下一行數(shù)據(jù)并重復(fù)這個(gè)過程。在流編輯器處理完流中的所有數(shù)據(jù)行后,它就會(huì)終止。
 ???????由于命令是按順序逐行給出的,sed編輯器只需對(duì)數(shù)據(jù)流進(jìn)行一遍處理就可以完成編輯操作。
 這使得sed編輯器要比交互式編輯器快得多,你可以快速完成對(duì)數(shù)據(jù)的自動(dòng)修改。
 ???????sed命令的格式如下。
 ???????sed options script file
 ???????選項(xiàng)允許你修改sed命令的行為,可以使用的選項(xiàng)已在表19-1中列出。
 
???????script參數(shù)指定了應(yīng)用于流數(shù)據(jù)上的單個(gè)命令。如果需要用多個(gè)命令,要么使用-e選項(xiàng)在命令行中指定,要么使用-f選項(xiàng)在單獨(dú)的文件中指定。有大量的命令可用來處理數(shù)據(jù)。我們將會(huì)在本章后面介紹一些sed編輯器的基本命令,然后在第21章中會(huì)看到另外一些高級(jí)命令。
1)在命令行定義編輯器命令
 ???????默認(rèn)情況下,sed編輯器會(huì)將指定的命令應(yīng)用到STDIN輸入流上。這樣你可以直接將數(shù)據(jù)通過管道輸入sed編輯器處理。這里有個(gè)簡(jiǎn)單的示例。
???????這個(gè)例子在sed編輯器中使用了s命令。s命令會(huì)用斜線間指定的第二個(gè)文本字符串來替換第一個(gè)文本字符串模式。在本例中是big test替換了test。
 ???????在運(yùn)行這個(gè)例子時(shí),結(jié)果應(yīng)該立即就會(huì)顯示出來。這就是使用sed編輯器的強(qiáng)大之處。你可以同時(shí)對(duì)數(shù)據(jù)做出多處修改,而所消耗的時(shí)間卻只夠一些交互式編輯器啟動(dòng)而已。
 ???????當(dāng)然,這個(gè)簡(jiǎn)單的測(cè)試只是修改了一行數(shù)據(jù)。不過就算編輯整個(gè)文件,處理速度也相差無幾。
???????sed命令幾乎瞬間就執(zhí)行完并返回?cái)?shù)據(jù)。在處理每行數(shù)據(jù)的同時(shí),結(jié)果也顯示出來了。可以在sed編輯器處理完整個(gè)文件之前就開始觀察結(jié)果。
 ???????重要的是,要記住,sed編輯器并不會(huì)修改文本文件的數(shù)據(jù)。它只會(huì)將修改后的數(shù)據(jù)發(fā)送到STDOUT。如果你查看原來的文本文件,它仍然保留著原始數(shù)據(jù)。
2)在命令行使用多個(gè)編輯器命令
 ???????要在sed命令行上執(zhí)行多個(gè)命令時(shí),只要用-e選項(xiàng)就可以了。
???????兩個(gè)命令都作用到文件中的每行數(shù)據(jù)上。命令之間必須用分號(hào)隔開,并且在命令末尾和分號(hào)之間不能有空格。
 ???????如果不想用分號(hào),也可以用bash shell中的次提示符來分隔命令。只要輸入第一個(gè)單引號(hào)標(biāo)示出sed程序腳本的起始(sed編輯器命令列表),bash會(huì)繼續(xù)提示你輸入更多命令,直到輸入了標(biāo)示結(jié)束的單引號(hào)。
???????必須記住,要在封尾單引號(hào)所在行結(jié)束命令。bash shell一旦發(fā)現(xiàn)了封尾的單引號(hào),就會(huì)執(zhí)行命令。開始后,sed命令就會(huì)將你指定的每條命令應(yīng)用到文本文件中的每一行上。
3)從文件中讀取編輯器命令
 ???????最后,如果有大量要處理的sed命令,那么將它們放進(jìn)一個(gè)單獨(dú)的文件中通常會(huì)更方便一些。可以在sed命令中用-f選項(xiàng)來指定文件。
???????在這種情況下,不用在每條命令后面放一個(gè)分號(hào)。sed編輯器知道每行都是一條單獨(dú)的命令。跟在命令行輸入命令一樣,sed編輯器會(huì)從指定文件中讀取命令,并將它們應(yīng)用到數(shù)據(jù)文件中的每一行上。
 
2.gawk程序
 ???????雖然sed編輯器是非常方便自動(dòng)修改文本文件的工具,但其也有自身的限制。通常你需要一個(gè)用來處理文件中的數(shù)據(jù)的更高級(jí)工具,它能提供一個(gè)類編程環(huán)境來修改和重新組織文件中的數(shù)據(jù)。這正是gawk能夠做到的。
 
???????gawk程序是Unix中的原始awk程序的GNU版本。gawk程序讓流編輯邁上了一個(gè)新的臺(tái)階,它提供了一種編程語言而不只是編輯器命令。在gawk編程語言中,你可以做下面的事情:
 ???????? 定義變量來保存數(shù)據(jù);
 ???????? 使用算術(shù)和字符串操作符來處理數(shù)據(jù);
 ???????? 使用結(jié)構(gòu)化編程概念(比如if-then語句和循環(huán))來為數(shù)據(jù)處理增加處理邏輯;
 ???????? 通過提取數(shù)據(jù)文件中的數(shù)據(jù)元素,將其重新排列或格式化,生成格式化報(bào)告。
 ???????gawk程序的報(bào)告生成能力通常用來從大文本文件中提取數(shù)據(jù)元素,并將它們格式化成可讀的報(bào)告。其中最完美的例子是格式化日志文件。在日志文件中找出錯(cuò)誤行會(huì)很難,gawk程序可以讓你從日志文件中過濾出需要的數(shù)據(jù)元素,然后你可以將其格式化,使得重要的數(shù)據(jù)更易于閱讀。
1)gawk命令格式
 ???????gawk程序的基本格式如下:
 ???????gawk options program file
 表19-2顯示了gawk程序的可用選項(xiàng)。
 
???????命令行選項(xiàng)提供了一個(gè)簡(jiǎn)單的途徑來定制gawk程序中的功能。我們會(huì)在探索gawk時(shí)進(jìn)一步
 了解這些選項(xiàng)。
 ???????gawk的強(qiáng)大之處在于程序腳本。可以寫腳本來讀取文本行的數(shù)據(jù),然后處理并顯示數(shù)據(jù),創(chuàng)
 建任何類型的輸出報(bào)告。
2)從命令行讀取程序腳本
 ???????gawk程序腳本用一對(duì)花括號(hào)來定義。你必須將腳本命令放到兩個(gè)花括號(hào)({})中。如果你錯(cuò)誤地使用了圓括號(hào)來包含gawk腳本,就會(huì)得到一條類似于下面的錯(cuò)誤提示。
???????由于gawk命令行假定腳本是單個(gè)文本字符串,你還必須將腳本放到單引號(hào)中。下面的例子在命令行上指定了一個(gè)簡(jiǎn)單的gawk程序腳本:
$ gawk '{print "Hello World!"}'???????這個(gè)程序腳本定義了一個(gè)命令:print命令。這個(gè)命令名副其實(shí):它會(huì)將文本打印到STDOUT。如果嘗試運(yùn)行這個(gè)命令,你可能會(huì)有些失望,因?yàn)槭裁炊疾粫?huì)發(fā)生。原因在于沒有在命令行上指定文件名,所以gawk程序會(huì)從STDIN接收數(shù)據(jù)。在運(yùn)行這個(gè)程序時(shí),它會(huì)一直等待從STDIN輸入的文本。
 ???????如果你輸入一行文本并按下回車鍵,gawk會(huì)對(duì)這行文本運(yùn)行一遍程序腳本。跟sed編輯器一樣,gawk程序會(huì)針對(duì)數(shù)據(jù)流中的每行文本執(zhí)行程序腳本。由于程序腳本被設(shè)為顯示一行固定的文本字符串,因此不管你在數(shù)據(jù)流中輸入什么文本,都會(huì)得到同樣的文本輸出。
???????要終止這個(gè)gawk程序,你必須表明數(shù)據(jù)流已經(jīng)結(jié)束了。bash shell提供了一個(gè)組合鍵來生成EOF(End-of-File)字符。Ctrl+D組合鍵會(huì)在bash中產(chǎn)生一個(gè)EOF字符。這個(gè)組合鍵能夠終止該gawk程序并返回到命令行界面提示符下。
3)使用數(shù)據(jù)字段變量
 ???????gawk的主要特性之一是其處理文本文件中數(shù)據(jù)的能力。它會(huì)自動(dòng)給一行中的每個(gè)數(shù)據(jù)元素分配一個(gè)變量。默認(rèn)情況下,gawk會(huì)將如下變量分配給它在文本行中發(fā)現(xiàn)的數(shù)據(jù)字段:
 ???????? $0代表整個(gè)文本行;
 ???????? $1代表文本行中的第1個(gè)數(shù)據(jù)字段;
 ???????? $2代表文本行中的第2個(gè)數(shù)據(jù)字段;
 ???????? $n代表文本行中的第n個(gè)數(shù)據(jù)字段。
 ???????在文本行中,每個(gè)數(shù)據(jù)字段都是通過字段分隔符劃分的。gawk在讀取一行文本時(shí),會(huì)用預(yù)定義的字段分隔符劃分每個(gè)數(shù)據(jù)字段。gawk中默認(rèn)的字段分隔符是任意的空白字符(例如空格或制表符)。
 ???????在下面的例子中,gawk程序讀取文本文件,只顯示第1個(gè)數(shù)據(jù)字段的值。
???????該程序用$1字段變量來僅顯示每行文本的第1個(gè)數(shù)據(jù)字段。
 ???????如果你要讀取采用了其他字段分隔符的文件,可以用-F選項(xiàng)指定。
???????這個(gè)簡(jiǎn)短的程序顯示了系統(tǒng)中密碼文件的第1個(gè)數(shù)據(jù)字段。由于/etc/passwd文件用冒號(hào)來分隔數(shù)字字段,因而如果要?jiǎng)澐珠_每個(gè)數(shù)據(jù)元素,則必須在gawk選項(xiàng)中將冒號(hào)指定為字段分隔符。
4) 在程序腳本中使用多個(gè)命令
 ???????如果一種編程語言只能執(zhí)行一條命令,那么它不會(huì)有太大用處。gawk編程語言允許你將多條命令組合成一個(gè)正常的程序。要在命令行上的程序腳本中使用多條命令,只要在命令之間放個(gè)分號(hào)即可。
???????第一條命令會(huì)給字段變量$4賦值。第二條命令會(huì)打印整個(gè)數(shù)據(jù)字段。注意, gawk程序在輸出中已經(jīng)將原文本中的第四個(gè)數(shù)據(jù)字段替換成了新值。也可以用次提示符一次一行地輸入程序腳本命令。
$ gawk '{ > $4="Christine" > print $0}' My name is Rich My name is Christine $???????在你用了表示起始的單引號(hào)后,bash shell會(huì)使用次提示符來提示你輸入更多數(shù)據(jù)。你可以每次在每行加一條命令,直到輸入了結(jié)尾的單引號(hào)。因?yàn)闆]有在命令行中指定文件名,gawk程序會(huì)從STDIN中獲得數(shù)據(jù)。當(dāng)運(yùn)行這個(gè)程序的時(shí)候,它會(huì)等著讀取來自STDIN的文本。要退出程序,只需按下Ctrl+D組合鍵來表明數(shù)據(jù)結(jié)束。
5)從文件中讀取程序
 ???????跟sed編輯器一樣,gawk編輯器允許將程序存儲(chǔ)到文件中,然后再在命令行中引用。
???????script2.gawk程序腳本會(huì)再次使用print命令打印/etc/passwd文件的主目錄數(shù)據(jù)字段(字段變量$6),以及userid數(shù)據(jù)字段(字段變量$1)。
 ???????可以在程序文件中指定多條命令。要這么做的話,只要一條命令放一行即可,不需要用分號(hào)。
???????script3.gawk程序腳本定義了一個(gè)變量來保存print命令中用到的文本字符串。注意,gawk程序在引用變量值時(shí)并未像shell腳本一樣使用美元符。
6)在處理數(shù)據(jù)前運(yùn)行腳本
 ???????gawk還允許指定程序腳本何時(shí)運(yùn)行。默認(rèn)情況下,gawk會(huì)從輸入中讀取一行文本,然后針對(duì)該行的數(shù)據(jù)執(zhí)行程序腳本。有時(shí)可能需要在處理數(shù)據(jù)前運(yùn)行腳本,比如為報(bào)告創(chuàng)建標(biāo)題。BEGIN關(guān)鍵字就是用來做這個(gè)的。它會(huì)強(qiáng)制gawk在讀取數(shù)據(jù)前執(zhí)行BEGIN關(guān)鍵字后指定的程序腳本。
???????這次print命令會(huì)在讀取數(shù)據(jù)前顯示文本。但在它顯示了文本后,它會(huì)快速退出,不等待任何數(shù)據(jù)。如果想使用正常的程序腳本中處理數(shù)據(jù),必須用另一個(gè)腳本區(qū)域來定義程序。
$ cat data3.txt Line 1 Line 2 Line 3 $ $ gawk 'BEGIN {print "The data3 File Contents:"} > {print $0}' data3.txt The data3 File Contents: Line 1 Line 2 Line 3 $???????在gawk執(zhí)行了BEGIN腳本后,它會(huì)用第二段腳本來處理文件數(shù)據(jù)。這么做時(shí)要小心,兩段腳本仍然被認(rèn)為是gawk命令行中的一個(gè)文本字符串。你需要相應(yīng)地加上單引號(hào)。
7)在處理數(shù)據(jù)后運(yùn)行腳本
 ???????與BEGIN關(guān)鍵字類似,END關(guān)鍵字允許你指定一個(gè)程序腳本,gawk會(huì)在讀完數(shù)據(jù)后執(zhí)行它。
???????當(dāng)gawk程序打印完文件內(nèi)容后,它會(huì)執(zhí)行END腳本中的命令。這是在處理完所有正常數(shù)據(jù)后給報(bào)告添加頁腳的最佳方法。
 ???????可以將所有這些內(nèi)容放到一起組成一個(gè)漂亮的小程序腳本文件,用它從一個(gè)簡(jiǎn)單的數(shù)據(jù)文件中創(chuàng)建一份完整的報(bào)告。
???????這個(gè)腳本用BEGIN腳本來為報(bào)告創(chuàng)建標(biāo)題。它還定義了一個(gè)叫作FS的特殊變量。這是定義字段分隔符的另一種方法。這樣你就不用依靠腳本用戶在命令行選項(xiàng)中定義字段分隔符了。
???????下面是這個(gè)gawk程序腳本的輸出(有部分刪節(jié))。
$ gawk -f script4.gawk /etc/passwd The latest list of users and shells UserID Shell -------- ------- root /bin/bash bin /sbin/nologin daemon /sbin/nologin [...] Christine /bin/bash mysql /bin/bash Samantha /bin/bash Timothy /bin/bash This concludes the listing $???????與預(yù)想的一樣,BEGIN腳本創(chuàng)建了標(biāo)題,程序腳本處理特定數(shù)據(jù)文件(/etc/passwd)中的信息,END腳本生成頁腳。
 ???????這個(gè)簡(jiǎn)單的腳本讓你小試了一把gawk的強(qiáng)大威力。
二.sed編輯器基礎(chǔ)
 ???????成功使用sed編輯器的關(guān)鍵在于掌握其各式各樣的命令和格式,它們能夠幫助你定制文本編輯行為。本節(jié)將介紹一些可以集成到腳本中基本命令和功能。
1.更多的替換選項(xiàng)
 ???????你已經(jīng)懂得了如何用s命令(substitute)來在行中替換文本。這個(gè)命令還有另外一些選項(xiàng)能讓事情變得更為簡(jiǎn)單。
1)替換標(biāo)記
 ???????關(guān)于替換命令如何替換字符串中所匹配的模式需要注意一點(diǎn)。看看下面這個(gè)例子中會(huì)出現(xiàn)什么情況。
???????替換命令在替換多行中的文本時(shí)能正常工作,但默認(rèn)情況下它只替換每行中出現(xiàn)的第一處。要讓替換命令能夠替換一行中不同地方出現(xiàn)的文本必須使用替換標(biāo)記(substitution flag)。替換標(biāo)記會(huì)在替換命令字符串之后設(shè)置。
 ???????s/pattern/replacement/flags
 ???????有4種可用的替換標(biāo)記:
 ???????? 數(shù)字,表明新文本將替換第幾處模式匹配的地方;
 ???????? g,表明新文本將會(huì)替換所有匹配的文本;
 ???????? p,表明原先行的內(nèi)容要打印出來;
 ???????? w file,將替換的結(jié)果寫到文件中。
 ???????在第一類替換中,可以指定sed編輯器用新文本替換第幾處模式匹配的地方。
???????將替換標(biāo)記指定為2的結(jié)果就是:sed編輯器只替換每行中第二次出現(xiàn)的匹配模式。g替換標(biāo)記使你能替換文本中匹配模式所匹配的每處地方。
$ sed 's/test/trial/g' data4.txt This is a trial of the trial script. This is the second trial of the trial script. $???????p替換標(biāo)記會(huì)打印與替換命令中指定的模式匹配的行。這通常會(huì)和sed的-n選項(xiàng)一起使用。
$ cat data5.txt This is a test line. This is a different line. $ $ sed -n 's/test/trial/p' data5.txt This is a trial line. $???????-n選項(xiàng)將禁止sed編輯器輸出。但p替換標(biāo)記會(huì)輸出修改過的行。將二者配合使用的效果就是只輸出被替換命令修改過的行。
 ???????w替換標(biāo)記會(huì)產(chǎn)生同樣的輸出,不過會(huì)將輸出保存到指定文件中。
???????sed編輯器的正常輸出是在STDOUT中,而只有那些包含匹配模式的行才會(huì)保存在指定的輸出文件中。
2) 替換字符
 ???????有時(shí)你會(huì)在文本字符串中遇到一些不太方便在替換模式中使用的字符。Linux中一個(gè)常見的例子就是正斜線(/)。
 ???????替換文件中的路徑名會(huì)比較麻煩。比如,如果想用C shell替換/etc/passwd文件中的bash shell,必須這么做:
???????由于正斜線通常用作字符串分隔符,因而如果它出現(xiàn)在了模式文本中的話,必須用反斜線來轉(zhuǎn)義。這通常會(huì)帶來一些困惑和錯(cuò)誤。
 ???????要解決這個(gè)問題,sed編輯器允許選擇其他字符來作為替換命令中的字符串分隔符:
???????在這個(gè)例子中,感嘆號(hào)被用作字符串分隔符,這樣路徑名就更容易閱讀和理解了。
2.使用地址
 ???????默認(rèn)情況下,在sed編輯器中使用的命令會(huì)作用于文本數(shù)據(jù)的所有行。如果只想將命令作用于特定行或某些行,則必須用行尋址(line addressing)。
 ???????在sed編輯器中有兩種形式的行尋址:
 ???????? 以數(shù)字形式表示行區(qū)間
 ???????? 用文本模式來過濾出行兩種形式都使用相同的格式來指定地址:
 ???????[address]command
 也可以將特定地址的多個(gè)命令分組:
 ???????address {
 ???????command1
 ???????command2
 ???????command3
 ???????}
 ???????sed編輯器會(huì)將指定的每條命令作用到匹配指定地址的行上。本節(jié)將會(huì)演示如何在sed編輯器腳本中使用兩種尋址方法。
1) 數(shù)字方式的行尋址
 ???????當(dāng)使用數(shù)字方式的行尋址時(shí),可以用行在文本流中的行位置來引用。sed編輯器會(huì)將文本流中的第一行編號(hào)為1,然后繼續(xù)按順序?yàn)榻酉聛淼男蟹峙湫刑?hào)。
 ???????在命令中指定的地址可以是單個(gè)行號(hào),或是用起始行號(hào)、逗號(hào)以及結(jié)尾行號(hào)指定的一定區(qū)間范圍內(nèi)的行。這里有個(gè)sed命令作用到指定行號(hào)的例子。
???????sed編輯器只修改地址指定的第二行的文本。這里有另一個(gè)例子,這次使用了行地址區(qū)間。
$ sed '2,3s/dog/cat/' data1.txt The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy dog $???????如果想將命令作用到文本中從某行開始的所有行,可以用特殊地址——美元符。
$ sed '2,$s/dog/cat/' data1.txt The quick brown fox jumps over the lazy dog The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy cat The quick brown fox jumps over the lazy cat $???????可能你并不知道文本中到底有多少行數(shù)據(jù),因此美元符用起來通常很方便。
2)使用文本模式過濾器
 ???????另一種限制命令作用到哪些行上的方法會(huì)稍稍復(fù)雜一些。sed編輯器允許指定文本模式來過濾出命令要作用的行。格式如下:
 ???????attern/command
 ???????必須用正斜線將要指定的pattern封起來。sed編輯器會(huì)將該命令作用到包含指定文本模式的行上。
 ???????舉個(gè)例子,如果你想只修改用戶Samantha的默認(rèn)shell,可以使用sed命令。
???????該命令只作用到匹配文本模式的行上。雖然使用固定文本模式能幫你過濾出特定的值,就跟上面這個(gè)用戶名的例子一樣,但其作用難免有限。sed編輯器在文本模式中采用了一種稱為正則表達(dá)式(regular expression)的特性來幫助你創(chuàng)建匹配效果更好的模式。
 ???????正則表達(dá)式允許創(chuàng)建高級(jí)文本模式匹配表達(dá)式來匹配各種數(shù)據(jù)。這些表達(dá)式結(jié)合了一系列通配符、特殊字符以及固定文本字符來生成能夠匹配幾乎任何形式文本的簡(jiǎn)練模式。
3)命令組合
 ???????如果需要在單行上執(zhí)行多條命令,可以用花括號(hào)將多條命令組合在一起。sed編輯器會(huì)處理地址行處列出的每條命令。
???????兩條命令都會(huì)作用到該地址上。當(dāng)然,也可以在一組命令前指定一個(gè)地址區(qū)間。
$ sed '3,${ > s/brown/green/ > s/lazy/active/ > }' data1.txt The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick green fox jumps over the active dog. The quick green fox jumps over the active dog. $???????sed編輯器會(huì)將所有命令作用到該地址區(qū)間內(nèi)的所有行上。
3.刪除行
 ???????文本替換命令不是sed編輯器唯一的命令。如果需要?jiǎng)h除文本流中的特定行,可以用刪除命令。
 ???????刪除命令d名副其實(shí),它會(huì)刪除匹配指定尋址模式的所有行。使用該命令時(shí)要特別小心,如果你忘記加入尋址模式的話,流中的所有文本行都會(huì)被刪除。
???????當(dāng)和指定地址一起使用時(shí),刪除命令顯然能發(fā)揮出最大的功用。可以從數(shù)據(jù)流中刪除特定的文本行,通過行號(hào)指定:
$ cat data6.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. $ $ sed '3d' data6.txt This is line number 1. This is line number 2. This is line number 4. $???????或者通過特定行區(qū)間指定:
$ sed '2,3d' data6.txt This is line number 1. This is line number 4. $???????或者通過特殊的文件結(jié)尾字符:
$ sed '3,$d' data6.txt This is line number 1. This is line number 2. $???????sed編輯器的模式匹配特性也適用于刪除命令。
$ sed '/number 1/d' data6.txt This is line number 2. This is line number 3. This is line number 4. $???????sed編輯器會(huì)刪掉包含匹配指定模式的行。
 
???????也可以使用兩個(gè)文本模式來刪除某個(gè)區(qū)間內(nèi)的行,但這么做時(shí)要小心。你指定的第一個(gè)模式會(huì)“打開”行刪除功能,第二個(gè)模式會(huì)“關(guān)閉”行刪除功能。sed編輯器會(huì)刪除兩個(gè)指定行之間的所有行(包括指定的行)。
$ sed '/1/,/3/d' data6.txt This is line number 4. $???????除此之外,你要特別小心,因?yàn)橹灰猻ed編輯器在數(shù)據(jù)流中匹配到了開始模式,刪除功能就會(huì)打開。這可能會(huì)導(dǎo)致意外的結(jié)果。
$ cat data7.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. This is line number 1 again. This is text you want to keep. This is the last line in the file. $ $ sed '/1/,/3/d' data7.txt This is line number 4. $???????第二個(gè)出現(xiàn)數(shù)字“1”的行再次觸發(fā)了刪除命令,因?yàn)闆]有找到停止模式,所以就將數(shù)據(jù)流中的剩余行全部刪除了。當(dāng)然,如果你指定了一個(gè)從未在文本中出現(xiàn)的停止模式,顯然會(huì)出現(xiàn)另外一個(gè)問題。
$ sed '/1/,/5/d' data7.txt $???????因?yàn)閯h除功能在匹配到第一個(gè)模式的時(shí)候打開了,但一直沒匹配到結(jié)束模式,所以整個(gè)數(shù)據(jù)流都被刪掉了。
4.插入和附加文本
 ???????如你所期望的,跟其他編輯器類似,sed編輯器允許向數(shù)據(jù)流插入和附加文本行。兩個(gè)操作的區(qū)別可能比較讓人費(fèi)解:
 ???????? 插入(insert)命令(i)會(huì)在指定行前增加一個(gè)新行;
 ???????? 附加(append)命令(a)會(huì)在指定行后增加一個(gè)新行。
 ???????這兩條命令的費(fèi)解之處在于它們的格式。它們不能在單個(gè)命令行上使用。你必須指定是要將行插入還是附加到另一行。格式如下:
???????new line中的文本將會(huì)出現(xiàn)在sed編輯器輸出中你指定的位置。記住,當(dāng)使用插入命令時(shí),文本會(huì)出現(xiàn)在數(shù)據(jù)流文本的前面。
$ echo "Test Line 2" | sed 'i\Test Line 1' Test Line 1 Test Line 2 $???????當(dāng)使用附加命令時(shí),文本會(huì)出現(xiàn)在數(shù)據(jù)流文本的后面。
$ echo "Test Line 2" | sed 'a\Test Line 1' Test Line 2 Test Line 1 $???????在命令行界面提示符上使用sed編輯器時(shí),你會(huì)看到次提示符來提醒輸入新的行數(shù)據(jù)。你必須在該行完成sed編輯器命令。一旦你輸入了結(jié)尾的單引號(hào),bash shell就會(huì)執(zhí)行該命令。
$ echo "Test Line 2" | sed 'i\ > Test Line 1' Test Line 1 Test Line 2 $???????這樣能夠給數(shù)據(jù)流中的文本前面或后面添加文本,但如果要向數(shù)據(jù)流內(nèi)部添加文本呢?
 ???????要向數(shù)據(jù)流行內(nèi)部插入或附加數(shù)據(jù),你必須用尋址來告訴sed編輯器你想讓數(shù)據(jù)出現(xiàn)在什么位置。可以在用這些命令時(shí)只指定一個(gè)行地址。可以匹配一個(gè)數(shù)字行號(hào)或文本模式,但不能用地址區(qū)間。這合乎邏輯,因?yàn)槟阒荒軐⑽谋静迦牖蚋郊拥絾蝹€(gè)行的前面或后面,而不是行區(qū)間的前面或后面。
 ???????下面的例子是將一個(gè)新行插入到數(shù)據(jù)流第三行前。
???????下面的例子是將一個(gè)新行附加到數(shù)據(jù)流中第三行后。
$ sed '3a\ > This is an appended line.' data6.txt This is line number 1. This is line number 2. This is line number 3. This is an appended line. This is line number 4. $???????它使用與插入命令相同的過程,只是將新文本行放到了指定的行號(hào)后面。如果你有一個(gè)多行數(shù)據(jù)流,想要將新行附加到數(shù)據(jù)流的末尾,只要用代表數(shù)據(jù)最后一行的美元符就可以了。
$ sed '$a\ > This is a new line of text.' data6.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. This is a new line of text. $???????同樣的方法也適用于要在數(shù)據(jù)流起始位置增加一個(gè)新行。只要在第一行之前插入新行即可。
 ???????要插入或附加多行文本,就必須對(duì)要插入或附加的新文本中的每一行使用反斜線,直到最后一行。
???????指定的兩行都會(huì)被添加到數(shù)據(jù)流中。
5.修改行
 ???????修改(change)命令允許修改數(shù)據(jù)流中整行文本的內(nèi)容。它跟插入和附加命令的工作機(jī)制一樣,你必須在sed命令中單獨(dú)指定新行。
???????在這個(gè)例子中,sed編輯器會(huì)修改第三行中的文本。也可以用文本模式來尋址。
$ sed '/number 3/c\ > This is a changed line of text.' data6.txt This is line number 1. This is line number 2. This is a changed line of text. This is line number 4. $???????文本模式修改命令會(huì)修改它匹配的數(shù)據(jù)流中的任意文本行。
$ cat data8.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. This is line number 1 again. This is yet another line. This is the last line in the file. $ $ sed '/number 1/c\ > This is a changed line of text.' data8.txt This is a changed line of text. This is line number 2. This is line number 3. This is line number 4. This is a changed line of text. This is yet another line. This is the last line in the file. $???????你可以在修改命令中使用地址區(qū)間,但結(jié)果未必如愿。
$ sed '2,3c\ > This is a new line of text.' data6.txt This is line number 1. This is a new line of text. This is line number 4. $???????sed編輯器會(huì)用這一行文本來替換數(shù)據(jù)流中的兩行文本,而不是逐一修改這兩行文本。
6.轉(zhuǎn)換命令
 ???????轉(zhuǎn)換(transform)命令(y)是唯一可以處理單個(gè)字符的sed編輯器命令。轉(zhuǎn)換命令格式如下。
 ???????[address]y/inchars/outchars/
 ???????轉(zhuǎn)換命令會(huì)對(duì)inchars和outchars值進(jìn)行一對(duì)一的映射。inchars中的第一個(gè)字符會(huì)被轉(zhuǎn)換為outchars中的第一個(gè)字符,第二個(gè)字符會(huì)被轉(zhuǎn)換成outchars中的第二個(gè)字符。這個(gè)映射過程會(huì)一直持續(xù)到處理完指定字符。如果inchars和outchars的長度不同,則sed編輯器會(huì)產(chǎn)生一條錯(cuò)誤消息。
 ???????這里有個(gè)使用轉(zhuǎn)換命令的簡(jiǎn)單例子。
???????如你在輸出中看到的,inchars模式中指定字符的每個(gè)實(shí)例都會(huì)被替換成outchars模式中相同位置的那個(gè)字符。
 ???????轉(zhuǎn)換命令是一個(gè)全局命令,也就是說,它會(huì)文本行中找到的所有指定字符自動(dòng)進(jìn)行轉(zhuǎn)換,而不會(huì)考慮它們出現(xiàn)的位置。
???????sed編輯器轉(zhuǎn)換了在文本行中匹配到的字符1的兩個(gè)實(shí)例。你無法限定只轉(zhuǎn)換在特定地方出現(xiàn)的字符。
7.回顧打印
 ???????介紹了如何使用p標(biāo)記和替換命令顯示sed編輯器修改過的行。另外有3個(gè)命令也能用來打印數(shù)據(jù)流中的信息:
 ???????? p命令用來打印文本行;
 ???????? 等號(hào)(=)命令用來打印行號(hào);
 ???????? l(小寫的L)命令用來列出行。
 ???????接下來的幾節(jié)將會(huì)介紹這3個(gè)sed編輯器的打印命令。
1)打印行
 跟替換命令中的p標(biāo)記類似,p命令可以打印sed編輯器輸出中的一行。如果只用這個(gè)命令,也沒什么特別的。
???????它所做的就是打印已有的數(shù)據(jù)文本。打印命令最常見的用法是打印包含匹配文本模式的行。
$ cat data6.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. $ $ sed -n '/number 3/p' data6.txt This is line number 3. $???????在命令行上用-n選項(xiàng),你可以禁止輸出其他行,只打印包含匹配文本模式的行。也可以用它來快速打印數(shù)據(jù)流中的某些行。
$ sed -n '2,3p' data6.txt This is line number 2. This is line number 3. $???????如果需要在修改之前查看行,也可以使用打印命令,比如與替換或修改命令一起使用。可以創(chuàng)建一個(gè)腳本在修改行之前顯示該行。
$ sed -n '/3/{ > p > s/line/test/p > }' data6.txt This is line number 3. This is test number 3. $???????sed編輯器命令會(huì)查找包含數(shù)字3的行,然后執(zhí)行兩條命令。首先,腳本用p命令來打印出原始行;然后它用s命令替換文本,并用p標(biāo)記打印出替換結(jié)果。輸出同時(shí)顯示了原來的行文本和新的行文本。
2)打印行號(hào)
 ???????等號(hào)命令會(huì)打印行在數(shù)據(jù)流中的當(dāng)前行號(hào)。行號(hào)由數(shù)據(jù)流中的換行符決定。每次數(shù)據(jù)流中出現(xiàn)一個(gè)換行符,sed編輯器會(huì)認(rèn)為一行文本結(jié)束了。
???????sed編輯器在實(shí)際的文本行出現(xiàn)前打印了行號(hào)。如果你要在數(shù)據(jù)流中查找特定文本模式的話,等號(hào)命令用起來非常方便。
$ sed -n '/number 4/{ > = > p > }' data6.txt 4 This is line number 4. $???????利用-n選項(xiàng),你就能讓sed編輯器只顯示包含匹配文本模式的行的行號(hào)和文本。
3)列出行
 ???????列出(list)命令(l)可以打印數(shù)據(jù)流中的文本和不可打印的ASCII字符。任何不可打印字符要么在其八進(jìn)制值前加一個(gè)反斜線,要么使用標(biāo)準(zhǔn)C風(fēng)格的命名法(用于常見的不可打印字符),比如\t,來代表制表符。
???????制表符的位置使用\t來顯示。行尾的美元符表示換行符。如果數(shù)據(jù)流包含了轉(zhuǎn)義字符,列出命令會(huì)在必要時(shí)候用八進(jìn)制碼來顯示。
$ cat data10.txt This line contains an escape character. $ $ sed -n 'l' data10.txt This line contains an escape character. \a$ $???????data10.txt文本文件包含了一個(gè)轉(zhuǎn)義控制碼來產(chǎn)生鈴聲。當(dāng)用cat命令來顯示文本文件時(shí),你看不到轉(zhuǎn)義控制碼,只能聽到聲音(如果你的音箱打開的話)。但是,利用列出命令,你就能顯示出所使用的轉(zhuǎn)義控制碼。
8.使用sed處理文件
 ???????替換命令包含一些可以用于文件的標(biāo)記。還有一些sed編輯器命令也可以實(shí)現(xiàn)同樣的目標(biāo),不需要非得替換文本。
 1)寫入文件
 ???????w命令用來向文件寫入行。該命令的格式如下:
 ???????[address]w filename
 ???????filename可以使用相對(duì)路徑或絕對(duì)路徑,但不管是哪種,運(yùn)行sed編輯器的用戶都必須有文件的寫權(quán)限。地址可以是sed中支持的任意類型的尋址方式,例如單個(gè)行號(hào)、文本模式、行區(qū)間或文本模式。
 ???????下面的例子是將數(shù)據(jù)流中的前兩行打印到一個(gè)文本文件中。
???????當(dāng)然,如果你不想讓行顯示到STDOUT上,你可以用sed命令的-n選項(xiàng)。
 ???????如果要根據(jù)一些公用的文本值從主文件中創(chuàng)建一份數(shù)據(jù)文件,比如下面的郵件列表中的,那么w命令會(huì)非常好用。
???????sed編輯器會(huì)只將包含文本模式的數(shù)據(jù)行寫入目標(biāo)文件。
???????你已經(jīng)了解了如何在sed命令行上向數(shù)據(jù)流中插入或附加文本。讀取(read)命令(r)允許你將一個(gè)獨(dú)立文件中的數(shù)據(jù)插入到數(shù)據(jù)流中。
???????讀取命令的格式如下:
???????[address]r filename
???????filename參數(shù)指定了數(shù)據(jù)文件的絕對(duì)路徑或相對(duì)路徑。你在讀取命令中使用地址區(qū)間,只能指定單獨(dú)一個(gè)行號(hào)或文本模式地址。sed編輯器會(huì)將文件中的文本插入到指定地址后。
???????sed編輯器會(huì)將數(shù)據(jù)文件中的所有文本行都插入到數(shù)據(jù)流中。同樣的方法在使用文本模式地址時(shí)也適用。
$ sed '/number 2/r data12.txt' data6.txt This is line number 1. This is line number 2. This is an added line. This is the second added line. This is line number 3. This is line number 4. $???????如果你要在數(shù)據(jù)流的末尾添加文本,只需用美元符地址符就行了。
$ sed '$r data12.txt' data6.txt This is line number 1. This is line number 2. This is line number 3. This is line number 4. This is an added line. This is the second added line. $???????讀取命令的另一個(gè)很酷的用法是和刪除命令配合使用:利用另一個(gè)文件中的數(shù)據(jù)來替換文件中的占位文本。舉例來說,假定你有一份套用信件保存在文本文件中:
$ cat notice.std Would the following people: LIST please report to the ship's captain. $???????套用信件將通用占位文本LIST放在人物名單的位置。要在占位文本后插入名單,只需讀取命令就行了。但這樣的話,占位文本仍然會(huì)留在輸出中。要?jiǎng)h除占位文本的話,你可以用刪除命令。結(jié)果如下:
$ sed '/LIST/{ > r data11.txt > d > }' notice.std Would the following people: Blum, R Browncoat McGuiness, A Alliance Bresnahan, C Browncoat Harken, C Alliance please report to the ship's captain. $現(xiàn)在占位文本已經(jīng)被替換成了數(shù)據(jù)文件中的名單。
總結(jié)
以上是生活随笔為你收集整理的初识sed和gawk的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: java -- 随机获取字母或者数字
 - 下一篇: python是一门跨平台语言_pytho