一、簡介
Bash Shell提供了功能強大的文件處理工具:sed(流編輯器stream editor)和awk,都可使用正則表達式進行模式匹配。而grep又有助於理解sed和awk。
二、grep命令
grep(Globel search Regular Expression and Print out the line)全面搜索正則表達式並把行打印出來,它是一種強大的文本搜索工具,與正則表達式結合使用。
1、格式選項
grep格式:grep [選項] [模式] [文件...],它在一個或多個文件中搜索滿足模式的文本行,grep的選項如下:
grep命令模式可以是字符串、變量或正則表達式,grep支持多文件查詢如grep pattern a.txt b.txt,grep指定多個文件時可以使用通配如grep pattern ?.txt,查找a.txt、b.txt等單個字符開頭的txt文件。
(1)-c選項
輸出匹配字符串行的數量,默認grep打印包含模式的所有行,加上-c就只顯示包含模式行的數量。如grep -c pattern *.txt。
(2)-n選項
列出所有的匹配行,並顯示行號,默認grep搜索單個文件只顯示每行內容,搜索多個文件顯示文件名及每行內容,加上-n將在內容前附加顯示行號(查詢中比較有用)。
(3)-v選項
顯示不包含模式的所有行,常與-c選項配合顯示不包含模式的行數。
(4)-h選項
默認下grep命令查詢多個文件時,在匹配行之前顯示文件名,加上-h選項,grep將不再顯示文件名。
(5)-r選項
默認情況,grep只對當前目錄下的文件進行搜索,而不對子目錄中的文件進行搜索。-r表示遞歸搜索,不僅搜索當前目錄而且搜索子目錄。比較有用。
(6)-w和-x選項
grep命令支持正則表達式,正則表達式的元字符被解釋成特殊的含義,-w選項使元字符不再被解釋爲特殊含義。例如:grep patt* a.txt,未加-w模式中的*被解析成任意字符,加上-w只搜索包含patt*字符串的文本行。
-x選項是匹配整行,文件中整行內容與模式匹配時才輸出,只有部分內容匹配也不輸出。
2、grep與正則表達式結合
(1)匹配行首元字符"^"表示行首,^$表空白行,[^$]表示空白行的範圍,前面加上"^"符號取反^[^$]表示非空白行。
(2)匹配重複字符
匹配重複字符通常可以利用"."符號表示一個任意字符和"*"符號表示任意個任意字符來實現,不是正則表達式的規則。
(3)轉義符
匹配的目標字符串中包含元字符,需要利用轉移符"\"屏蔽其意義,如grep "com\.con" *,句號"."字符是元字符,需要在之前加上轉移符進行轉義。
橫槓(-)字符比較特殊,它雖不屬於元字符,但grep命名是由"-"字符引出的特殊字符,因此需要用轉移符將其轉義。
(4)POSIX字符類
爲了保持不同國家的字符編碼一致性,POSIX增加了特殊的字符類,grep支持POSIX字符類。
[:upper:]表示大寫字母集合,[[:upper:]]表示匹配字符集合,grep ^[[:upper:]] a.txt,搜索以大寫字母開頭的文本行;grep ^[[:space:]] a.txt,搜索以空格開頭的文本行。
(5)精確匹配
\<\>符號用於精確匹配,grep "\<the\>" file,精確匹配the這個單詞,未加列出所有包含the字符串的行。grep命令的-w選項也可用於精確匹配。
(6)或字符
或字符"|"是擴展正則表達式中定義的,grep需要加上-E選項才能支持它,不帶-E選項,會將"|"字符解析爲字面意義。
3、egrep和fgrep
(1)grep命令族:grep(支持基本正則表達式)、egrep(等價grep -E)(擴展grep命令,支持基本和擴展正則表達式)、fgrep(等價grep -F)(快速grep命令,不支持正則表達式,按字符串的字面意思進行匹配)。(2)egrep "^-+B" a.txt,查找以"-"開頭且至少重複一次然後加B字符的字符串,"+"至少重複一次,"*"重複0次或無數次。
(3)grep命令功能十分強大,以代替egrep和fgrep命令。
三、sed命令
sed是一個非交互式的文本編輯器,可對文本文件和標準輸入進行編輯,sed只是對緩衝區中原始文件的副本進行編輯,並不編輯原始的文件,若需要保存改動內容則需要重定向到另一個文件。sed使用於:編輯相對交互式文本編輯器而言太大的文件、編輯命令複雜在交互式下難輸入、對文件掃描一次但需執行多個編輯函數的情況。
1、sed命令基本用法
(1)調用sed方式一:在shell命令行調用sed,格式爲:sed [選項] 'sed命令' 輸入文件。
方式二:將sed命令插入腳本後,然後通過sed命令調用它,格式爲:sed [選項] -f sed腳本文件 輸入文件。
方式三:將sed命令插入腳本後,執行改腳本,格式爲:./sed腳本文件 輸入文件。
sed的-n選項,sed編輯命令p實現打印匹配行功能,-n表示不打印sed編輯對象的全部內容,例如:sed '1p' string.txt,不僅打印第一行數據,而且然後將string.txt的全部內容打印到標準輸出;sed -n '1p' string.txt僅打印第一行內容;sed -n '3,6p' string.txt打印3~6行數據;sed -n '/pattern/p'
string.txt打印匹配模式行。
sed的-e選項,將下一個字符串解析爲sed編輯命令,若只傳遞一個編輯命令給sed,-e可省略。例如:需要將匹配pattern關鍵字的內容和行號都打印出來,就要想sed傳遞"p"和"="兩個編輯命令,sed -n -e '/pattern/p' -e '/pattern/=' string.txt,帶多個編輯命令的sed格式只能是:sed [選項] -e 編輯命令1 -e編輯命令2 ... -e 編輯命令n 輸入文件。
sed的-f選項,只有在調用sed腳本文件時才起作用。其中先介紹sed編輯命令a\符號用於追加文本,sed '指定地址a\text' 輸入文件,例如sed '/file:/a\append data.' string.txt,匹配模式file:字符串然後在其行後追加文本內容append data.追加文本只是輸出到標準輸出上,原始文件未改變。接着編寫sed腳本文件,新建append.sed的文件
#!/bin/sed -f
/file:/a\
append data.\
another line.
執行腳本,需加上輸入文件的名稱,./append.sed string.txt。
(2)sed命令通常由定位文件行和sed編輯命令兩部分組成,sed編輯命令對定位文本行進行各種處理。
sed定位文本方法:
(3)sed編輯命令標識對文本進行各種處理,如打印、刪除、追加、插入、替換等。sed的基本編輯命令可以放在單引號內也可以放在單引號外。
2、sed文本定位
(1)匹配元字符若sed命令所要匹配的目標字符串中包含元字符,需要使用轉義符"\"屏蔽其特殊意義。例如sed -n '/\$/p' string.txt匹配$符號。
(2)使用元字符進行匹配
$在正則表達式中表示行尾,在sed命令中卻表示最後一行,例如sed -n '$p' string.txt匹配最後一行。
(3)!符號
!符號表示取反,x,y!表示匹配不在x和y行號範圍內的行,sed -n '2,10!p' string.txt表示不打印2~10之間的行。
(4)使用行號與關鍵字匹配限定行範圍
/pattern/,x和x,/pattern/兩種形式限定行號與關鍵字匹配行之間的範圍,與x,y是一樣的,只是將x或y用/pattern/代替而已。例如sed -n '/pattern/,$p' string.txt表示文件string.txt從匹配pattern行到最後一行。
3、sed基本編輯命令
(1)插入文本
插入文本和追加文本類似,區別在於追加在匹配行後面插入,而插入文本是在匹配行的前面插入,插入文本的格式:sed '指定地址i\text' 輸入文件,新建insert.sed腳本:
#!/bin/sed -f
/file:/i\
we insert a new line.
(2)修改文本
指將所匹配的文本行利用新文本代替,修改文本的格式爲:sed '指定地址c\text' 輸入文件,新建modify.sed的腳本:
#!/bin/sed -f
/file:/c\
we modify this line.
(3)刪除文本
sed刪除文本命令可以將指定行或指定行範圍進行刪除,刪除格式:sed '指定地址d' string,d後面不帶\符號,例如sed '2,$d' string.txt,刪除第2行到最後一行。
(4)替換文本
sed替換文本操作將所匹配的文本行利用新文本替換,與修改文本功能類似,區別在於:替換文本可以替換一個字符串而修改文本是對整行進行修改。sed編輯命令的替換文本符號爲s,格式爲:s/被替換的字符串/新字符串/[替換選項]
sed -n 's/被替換的字符串/新字符串/p' 輸入文件,只打印替換行。
g選項使得sed替換命令對某行的所有關鍵字都進行替換,只有被替換字符串所在行出現2次及其以上g選項纔有用。sed替換命令還可指定替換第幾次匹配的關鍵字,替換選項上加相應數字,數字在1~512之間。
w選項後加文件名錶示將輸出定向到這個文件,若輸出文件未建立sed命令自動建立輸出文件,默認目錄是當前工作目錄。例如sed -n 's/old/new/w output' input。
&符號可用來保存被替換的字符串以供調用,例如sed -n 's/seu/&.new/pg' string.txt等價於sed -n 's/seu/seu.new/pg' string.txt,都是使用seu.new替換seu,&符號保存了被替換字符串seu的值。
(5)寫入一個新文件
要保存編輯結果,需將編輯後的文本重定向到另一個文件,sed寫入文件的符號爲w,格式爲:指定地址 w 文件名,例如sed -n '1,5 w output' input,input文件中的1~5行寫入output文件。sed -n '/pattern/w output' input,將匹配pattern模式的行寫入文件。
(6)從文件中讀入文本
sed命令還可將其他文件中的文本讀入,並附加在指定地址,格式爲:指定地址 r 文件名,例如sed '/pattern/r otherfile' input,在匹配pattern模式行的後面加上otherfile的所有內容。
(7)退出命令
sed命令的q選項表示完成指定地址的匹配後立即退出,格式爲:指定地址 q,sed -n '/r*/p' input,匹配全部的字符串,sed -n ''/r*/q' input,匹配第1個字符串後立即退出。
(8)變換命令
sed命令的y選項表示字符變換,對字符的逐個處理,格式爲:sed 'y/被變換的字符序列/變換的字符序列/' 輸入文件,要求被變換的字符序列和變換的字符序列等長,例如sed 'y/12345/ABCDE/' input,將input文件中1變換A、2變換爲B、3變換成C、4變換成D、5變換成E。
(9)顯示控制字符
控制字符就是非打印字符,如退格鍵、F1鍵、Shift鍵等,sed 1顯示文件中的控制字符,例如sed -n '1,$1' file,表示打印從第1行到最後一行的控制字符。
(10)在定位行執行命令組
sed編輯命令中的"{}"符號可以指定在定位行上所執行的命令組,它的作用與sed的-e選項類似,都是爲了在定位行執行多個編輯命令。例如sed -n -e '/pattern/p' -e '/pattern/=' input與sed -n '/pattern/{p;=}' input等價。
4、sed高級編輯命令
(1)處理匹配行的下一行sed編輯命令n的意義是讀取下一個輸入行,用n後面的一個命令處理該行,例如sed '/pattern/{n;s/old/new/;}' input,即找出pattern關鍵字的匹配行,然後在匹配行的下一行執行s/old/new將下一行的old替換成new命令。
(2)sed緩衝區的處理
sed有兩種緩衝區:模式緩衝區(Pattern Buffer)和保持緩衝區(Hold Buffer),sed的一些編輯命令可以對保持緩衝區進行處理,比與模式緩衝區的內容互換。例如sed -e '/Subject/h' -e '/seugrid/x' -e '$G' input,匹配Subject將此行保持緩衝區,接着匹配seugrid將此行寫入保持緩衝區並將原來保持緩衝區的內容輸出,最後到最後一行時輸出保持緩衝區的內容。
(3)利用分號分隔多個編輯命令
除了使用上述-e和{}可以實現sed的多編輯命令,還可以利用分號(;)實現類似功能,格式爲:sed '編輯命令1;編輯命令2;...' 輸入文件,例如sed 's/globel/GLOBEL/; s/pattern/PATTERN/' input,完成兩個替換操作,等價於-e命令引出的多個編輯命令。 也可在shell二級命令提示符下連續輸入多條編輯命令。
四、awk命令
awk用來進行文本處理,可以從文件或字符串中基於指定規則瀏覽和抽取信息。awk是最難掌握的一種Shell文本處理工具,其中包含了太多的編程細節。首先要掌握awk語言的基本語法,在shell中熟練使用awk。最新的是gawk,awk實際上是/bin/gawk的鏈接。
1、awk編程模型
awk程序由一個主輸入循環維持(awk已搭好主輸入循環框架,代碼一般被嵌到其中執行),主輸入循環反覆執行直到終止條件被觸發。
awk定義了兩個特殊的字符:BEGIN和END,BEGIN用於在主輸入循環之前執行(即在未讀取輸入文件行之前執行),END剛好相反用在主輸入循環之後執行(即在讀取輸入文件行完畢後執行)。簡單地將awk編程模型分爲三個階段:
2、awk調用方法
調用awk的方法與sed類似,也有三種。方式一:shell命令行輸入命令調用awk,格式爲:awk [-F 域分隔符] 'awk程序段' 輸入文件。方式二:將awk程序段插入腳本文件,然後通過awk命令調用它,格式爲:awk -f awk腳本文件 輸入文件。方式三:將sed命令插入腳本文件後,執行該腳本./awk腳本文件 輸入文件(awk腳本仍以#!/bin/gawk符號開頭)。
3、awk編程
(1)awk模式匹配
awk語句都由模式(pattern)和動作(action)組成。模式是一組用於測試輸入行是否需要執行動作的規則,動作是包含語句、函數和表達式的執行過程。awk模式匹配需使用正則表達式,支持"?"和"+"兩種擴展字符(grep和sed不支持)。
例如:awk '/^$/{print "This is blank."}' input,表示一旦讀入文件行是空行就打印This is blank。awk由兩部分組成,以/符號分隔,^$(是正則表達式是空白行)部分是模式;花括號部分是動作,是打印操作;input是文件名稱。
awk第二種調用方式,新建source.awk輸入/^$/{print "This is blank."},然後調用awk -f source.awk input。
awk第三種調用方式,vim source.awk
#!/bin/awk -f
/^$/{print "This is blank."}
然後執行./source.awk input。
(2)記錄和域
awk認爲輸入文件是結構化的,awk定義域操作符$來指定執行動作的域,域操作符$後面跟數字或變量來標識域的位置,每條記錄的域從1開始編號,$1表示第1個域,$2表示第2個域,$0表示所有的域。
例如awk '{print $1,$2}' file,打印指定域;awk -F“\t” '{print $0}' file,打印全部域,默認的分隔符是空格鍵,使用-F選項來改變分隔符(小寫-f表示調用awk腳本),也可以在BEGIN字段中設置FS的值來改變分隔符,如awk 'BEGIN{FS=","} {print $0}' file。特殊的是對FS賦值FS="\t+"表示一個或多個Tab鍵作爲分隔符。
域操作符$後面還可以跟變量,或者變量運算表達式,如awk 'BEGIN{one=1;two=2} {print $(one+two)}' file,BEGIN字段在遍歷輸入文件之前執行。
(3)關係和布爾表達式
awk定義了一組關係運算符用於awk模式匹配。
例:awk 'BEGIN {FS=":"} $1~/root/' /etc/passwd,打印/etc/passwd文件中第1個域匹配root關鍵字的記錄;awk 'BEGIN {FS=":"} $0!~/root/' /etc/passwd,打印文件所有域不匹配root關鍵字的記錄。
awk在進行模式匹配時,會用到條件語句if、if/else、if/else else三種語句,如awk 'BEGIN {FS=":"} {if($3<$4) print $0}' /etc/passwd,利用if語句匹配第3個域小於第4個域的記錄。
爲進行多條件模式匹配,awk定義了三個布爾運算符表示多條件之間的關係。
例awk 'BEGIN {FS=":"} {if($3==10 || $4==10) print $0}' /etc/passwd,查找滿足條件$3==10或$4==10的記錄。其中==進行的匹配稱爲精確匹配,若{if($3~10 || $4~10) print $0表示模糊匹配,查找包含10字符的記錄。
(4)表達式
一個awk表達式可由數值、字符常量、變量、操作符、函數和正則表達式自由組合而成。表達式可進行變量和數字之間的算術操作。
例如awk '/^$/{print x+=1}' file,匹配空白行就輸出空白行個數,等價於awk '/^$/{print x++}' file。
寫名爲source.awk的腳本用於計算student中每個學生的平均成績,腳本內容爲:
#!/bin/awk -f
BEGIN {FS=","}
{total=$4+$5+$6+$7+$8
avg=total/5
print $1,avg
}
執行腳本./source.awk student。
(5)系統變量
awk定義了很多內建變量用於設置環境信息,分爲兩種:一種用於改變awk的默認值,如域分隔符;一種用於定義系統值,在處理文本時可以讀取這些系統值,如記錄中的域數量、當前記錄數、當前文件名等。awk環境變量意義如下:
例awk 'BEGIN{FS=","} {print NF,FR,$0} END {print FILENAME}' file,NF爲記錄的域數量,NR顯示當前的記錄數,$0表示打印記錄的所有域,END字段打印保存當前輸入文件名的FILENAME。
(6)格式化輸出
awk的一大主要功能是產生報表,報表就要按預定格式輸出,awk定義了printf輸出語句,規定了輸出的格式。printf (格式控制符,參數),格式控制符以%符號開始,分爲awk修飾符和格式符兩種。
例如awk 'BEGIN {FS=","} {print("%s\t%d\n", $2, $8)}' file,從域號2和8獲取相應的值。
例如awk 'BEGIN {FS=","} {printf("%-15s\t%s\n", $1, $3)}' file,-15表示該字符串長度控制爲15位並且左對齊,如字符串不足15位則用空格補全,也可以在BEGIN字段中添加相應的輸出註釋,如awk 'BEGIN {FS=",";print "Name\t\tPhoneNumber"} {printf("%-10.3f\t%s\n", $1,
$3)}' file。%-10.3表示浮點數長度控制在10位、小數點後保留3位,左對齊。
(7)內置字符串函數
awk提供了強大的內置字符串函數,用於實現文本的字符串替換、查找以及分隔等功能。
gsub有兩種形式,第一種形式作用於全部域即$0,第二種形式作用於域t。例awk 'BEGIN {FS=":";OFS=":"} gsub(/root/, "gridsphere", $1) {print $0}' /etc/passwd,將第1個域上的字符串替換。
index返回第二個字符串在第一個字符串出現的首位置,length返回字符串的長度。如
match(s, t)測試s是否包含匹配t的字符串,t可以是一個正則表達式,匹配成功返回匹配t的首位置,不成功返回0。例awk 'BEGIN{IGNORECASE=1; print match("helloworld", /w/)}'忽略大小寫匹配字符串w。
sub(r,s,t)將t中第1次出現的r替換爲s(r可爲正則表達式),substr返回字符串的指定後綴awk 'BEGIN{str="code programming";print substr(str,6)},返回從第6個字符開始的後綴部分;substr(str, 6, 9),返回從第6個字符開始長度爲9的後綴部分。
(8)awk腳本傳遞參數
awk腳本內的變量可以在命令行中進行賦值,實現向awk腳本傳遞參數,變量賦值放在腳本之後、輸入文件之前。格式爲:awk 腳本 parameter=value 輸入文件。
例如:awk 'BEGIN {FS=","} {print NR, $0}' OFS="." file,每條記錄前加上了行號(NR值),然後重新定義OFS改變輸出域的分隔符。
命令行參數不能被BEGIN字段語句訪問,即直到輸入文件的第1行被讀取時,命令行參數方纔生效。原因是awk讀到命令行參數的賦值語句時,並不清楚是一個命令行參數的賦值語句只是認爲是一個無效的文件名,awk繼續讀取直到正確的輸入文件名被解析才判定前面的語句是命令行參數的賦值語句。
上述命令在讀到n=1這條賦值語句時,它將n=1作爲輸入文件名,該命令在讀取n=1文件前執行BEGIN字段,此時n爲空,因此打印一行空白行。接着該命令發現n=1並非有效的文件名繼續讀取到source.txt參數並發現source.txt是一個有效的文件名,進而將n=1解析爲命令行參數賦值語句,打印滿足n==1的語句。
(9)條件語句和循環語句
awk的條件語句if的語法:
if (條件表達式)
動作1
[else
動作2]
條件表達式可以包括算術、關係和布爾操作符。也可以使用"~"匹配符和正則表達式作爲if語句的條件,例if (x ~ /[Hh]el?o/) print x。
awk的循環語句有三種:while、do while和for。
while(條件表達式)
動作
、
do
動作
while(條件表達式)
、
for(設置計數器初值;測試計數器;計數器變化)
動作
(10)數組
數組是用於存儲一系列值的變量,可通過索引來訪問數組的值,索引需要用中括號括起,格式爲:array[index]=value。數組無須定義數組類型和大小而可以直接賦值後使用。
關聯數組,指數組的索引可以是字符串也可以是數字,對每一個數組元素awk自動維護一對值:索引和數組元素值。關聯數組的值無須以連續的地址進行存儲。字符串和數字之間的差別是明顯的,如array[9]不能指定到與array[09]相同的值。例awk 'BEGIN{data[10.15]="1200";CONVFMT="%d";printf("<%s>\n", data[10.15])}',利用CONVFMT系統變量將10.15轉換成整數,data[10]就不能夠取得1200了。
awk定義了一種for循環用來訪問關聯數組,語法如下:
for (variable in array)
do something with array[variable]
其中關鍵字in也可用在條件表達式中判斷元素是否在數組中,index in array,如果array[index]存在返回1否則返回0。例awk 'BEGIN{data[10.15]="1200"; if ("10.15" in data) print "found element."} '。
split(r,s,t)函數將字符串以t爲分隔符,將r字符串拆分爲字符串數組,並存放在s中,返回值是split數組的大小。例awk 'BEGIN {print split("abc/def/xyz", str, "/")}',輸出值爲3。
新建array.awk腳本文件:
#!/bin/awk -f
BEGIN {FS=","}
{split($1, name, " ");
for(i in name) print name[i]}
執行腳本./array.awk filename,將輸出name數組的所有內容。
awk系統變量中有兩個變量是以數組形式提供的:ARGV和ENVIRON,ARGC是ARGV數組中元素的個數,從ARGV[0]開始到ARGV[ARGC-1]結束。新建名爲argv.awk腳本,內容如下:
BEGIN { for(x=0;x<ARGC;x++)
print ARGV[x]
print ARGC
}
shell中執行awk -f argv.awk xyz n=100 2014,有三個參數分別在ARGV[1]~ARGV[3]中,argc爲4。
ENVIRON變量存儲了Linux操作系統的環境變量,awk 'BEGIN {for (i in ENVIRON) print i "=" ENVIRON[i]}',顯示當前系統所定義的環境變量,ENVIRON的索引是環境變量名,所以可以通過環境變量名直接得到其值,也可以通過ENVIRON數組改變環境變量的值如EVNIRON["PATH"]=/bin/gawk,其中環境變量名需要用雙引號引起。
五、總結
(1)sed用於流編輯將一系列的編輯命令作用於緩衝區中輸入文件的副本,awk最顯著特點是處理結構化文件
(2)sed和awk與管道緊密結合,後續將加深理解。