天天看點

shell學習筆記2---awk字元串處理(原創)

awk内置字元串函數

gsub(r,s) 在整個$0中用s替代r;gsub(r,s,t) 在整個t中用s替代r

gsub函數有點類似于sed查找和替換。它允許替換一個字元串或字元為另一個字元串或字元,并以正規表達式的形式執行。第一個函數作用于記錄$0,第二個gsub函數允許指定目标,然而,如果未指定目标,預設為$0。

index(s,t):函數傳回目标字元串s中查詢字元串t的首位置。

length(s) :傳回s長度

match(s,r): 測試s是否包含比對r的字元串

split(s,a,fs) 在fs上将s分成序列a

sprint (fmt,exp) :函數類似于printf函數(以後涉及),傳回基本輸出格式fmt的結果字元串exp。

sub(r,s) 用$0中最左邊最長的子串代替s

substr(s,p) 傳回字元串s中從p開始的字尾部分

substr(s,p,n) 傳回字元串s中從p開始長度為n的字尾部分。

match函數測試字元串s是否包含一個正規表達式r定義的比對。

split使用域分隔符fs将字元串s劃分為指定序列a。

1.gsub

要在整個記錄中替換一個字元串為另一個,使用正規表達式格式, /目标模式/,替換模式/。例如改變學生序号4842到4899:

$cat grade.txt

m.tans 5/99 48311 green 8 40 44

j.lulu 06/99 48317 green 9 24 26

p.bunny 02/99 48 yellow 12 35 28

j.troll 07/99 4842 brown-3 12 26 26

l.tansl 05/99   4712 brown-2 12 30 28

# cd /usr/sam

# awk 'gsub(/4842/,4899){print $0}' grade.txt

j.troll 07/99 4899 brown-3 12 26 26

2. index

查詢字元串s中t出現的第一位置。必須用雙引号将字元串括起來。例如傳回目标字元串bunny中ny出現的第一位置,即字元個數。

# awk 'begin {print index("bunny","ny")}' grade.txt

4

3. length

傳回所需字元串長度,例如檢驗字元串j.troll傳回名字及其長度,即人名構成的字元個數

# awk '$1=="j.troll" {print length($1)" "$1}' grade.txt

7 j.troll

還有一種方法,這裡字元串加雙引号。

# awk 'begin{print length("a few good men")}'

14

4. match

match測試目标字元串是否包含查找字元的一部分。可以對查找部分使用正規表達式,傳回值為成功出現的字元排列數。如果未找到,傳回0,第一個例子在ancd中查找d。因其不存在,是以傳回0。第二個例子在ancd中查找d。因其存在,是以傳回ancd中d出現的首位置字元數。第三個例子在學生j.lulu中查找u。

# awk 'begin{print match("ancd",/d/)}'

# awk '$1=="j.lulu" {print match($1,"u")}' grade.txt

5. split

使用split傳回字元串數組元素個數。工作方式如下:如果有一字元串,包含一指定分隔符-,例如ad2-kp9-ju2-lp-1,将之劃分成一個數組。使用split,指定分隔符及數組名。此例中,指令格式為("ad2-kp9-ju2-lp-1",parts_array,"-"),split然後傳回數組下标數,這裡結果為4。

# awk 'begin {print split("123-456-789",pats_array,"-")}'

3

還有一個例子使用不同的分隔符。

# awk 'begin {print split("123#456#789",myarray,"#")}'                    

這個例子中,split傳回數組myarray的下标數。數組myarray取值如下:

myarray[1]=123

myarray[2]=456

myarray[3]=789

6. sub

使用sub發現并替換模式的第一次出現位置。字元串str包含'poped popo pill',執行下列sub指令sub(/op/,"op",str)。模式op第一次出現時,進行替換操作,傳回結果如下:'poped pope pill'。

如:學生j.troll的記錄有兩個值一樣,"目前級别分"與"最進階别分"。隻改變第一個為29,第二個仍為26不動,操作指令為sub(/26/,"29",$0),隻替換第一個出現26的位置。注意j.troll記錄需存在。

# awk '$1=="j.troll" sub(/26/,"29",$0)' grade.txt

j.lulu 06/99 48317 green 9 24 29

j.troll 07/99 4842 brown-3 12 29 26

l.tansl 05/99 4712 brown-2 12 30 28

7. substr

substr是一個很有用的函數。它按照起始位置及長度傳回字元串的一部分。例子如下:

# awk '$1=="l.tansl" {print substr($1,1,3)}' grade.txt

l.t

上面例子中,指定在域1的第一個字元開始,傳回其前面3個字元。

如果給定長度值遠大于字元串長度, awk将從起始位置傳回所有字元,要抽取ltansl-ey的姓,隻需從第3個字元開始傳回長度為7。可以輸入長度99,awk傳回結果相同。

# awk '$1=="l.tansl" {print substr($1,1,99)}' grade.txt

l.tansl

substr的另一種形式是傳回字元串字尾或指定位置後面字元。這裡需要給出指定字元串及其傳回字串的起始位置。例如,從文本檔案中抽取姓氏,需操作域1,并從第三個字元開始:

# awk '{print substr($1,3)}' grade.txt

tans

lulu

bunny

troll

tansl

還有一個例子,在begin部分定義字元串,在end部分傳回從第t個字元開始抽取的子串。

# awk 'begin{str="a few good men"}end{print substr(str,7)}' grade.txt

good men

8. 從shell中向awk傳入字元串

awk腳本大多隻有一行,其中很少是字元串表示的。大多要求在一行内完成awk腳本,這一點通過将變量傳入awk指令行會變得很容易。現就其基本原理講述一些例子。

使用管道将字元串stand-by傳入awk,傳回其長度。

# echo "stand-by" | awk '{print length($0)}'

8

設定檔案名為一變量,管道輸出到awk,傳回不帶擴充名的檔案名。

# str="mydoc.txt"

# echo $str|awk '{print substr($str,1,5)}'

mydoc

設定檔案名為一變量,管道輸出到awk,隻傳回其擴充名。

# echo $str|awk '{print substr($str,7)}'

txt

字元串屏蔽序列

使用字元串或正規表達式時,有時需要在輸出中加入一新行或查詢一進制字元。列印一新行時(新行為字元\n),給出其屏蔽序列,以不失其特殊含義,用法為在字元串前加入反斜線。例如使用\n強迫列印一新行。

如果使用正規表達式,查詢花括号({ }),在字元前加反斜線,如/\{/,将在awk中失掉其特殊含義。

awk中使用的屏蔽序列

\b 倒退鍵

\t tab鍵

\f 走紙換頁

\ddd 八進制值

\n 新行

\c 任意其他特殊字元,例如\ \為反斜線符号

\r Enter鍵

使用上述符号,列印may day,中間夾tab鍵,後跟兩個新行,再列印may day,但這次使用八進制數104、141、171分别代表d、a、y。

# awk 'begin {print"\nmay\tday\n\nmay\t\104\141\171"}'

may     day

注意,\104為d的八進制ascii碼,\141為a的八進制ascii碼,等等。

awk輸出函數printf

目前為止,所有例子的輸出都是直接到螢幕,除了tab鍵以外沒有任何格式。awk提供函數printf,擁有幾種不同的格式化輸出功能。例如按列輸出、左對齊或右對齊方式。

每一種printf函數(格式控制字元)都以一個%符号開始,以一個決定轉換的字元結束.轉換包含三種修飾符。

printf函數基本文法是printf([格式控制符],參數),格式控制字元通常在引号裡。

printf修飾符

-                 左對齊

width         域的步長,用0表示0步長

.prec          最大字元串長度,或小數點右邊的位數

awk printf格式

%c            ascii字元

%d           整數

%e           浮點數,科學記數法

%f            浮點數,例如(1 2 3 . 4 4)

%g           awk決定使用哪種浮點數轉換e或者f

%o           八進制數

%s           字元串

%x           十六進制數

1. 字元轉換

觀察ascii碼中65的等價值。管道輸出65到awk。printf進行ascii碼字元轉換。這裡也加入換行,因為預設情況下printf不做換行動作。

$echo "65" | awk '{printf "%c\n",$0}'

a

按同樣方式使用awk得到同樣結果。

$awk 'begin{printf "%c\n",65}'

所有的字元轉換都是一樣的,下面的例子表示進行浮點數轉換後'999'的輸出結果。整數傳入後被加了六個小數點。

$awk 'begin{printf "%f\n",999}'

999.000000

2. 格式化輸出

列印所有的學生名字和序列号,要求名字左對齊, 15個字元長度,後跟序列号。注意\n換行符放在最後一個訓示符後面。輸出将自動分成兩列。

# awk '{printf "%-15s %s\n",$1,$3}' grade.txt

m.tans          48311

j.lulu          48317

p.bunny         48

j.troll         4842

l.tansl         4712

加入一些文本注釋幫助了解封包含義。可在正文前嵌入頭資訊。注意這裡使用print加入頭資訊。如果願意,也可使用printf。

# awk 'begin{print "name\t\ts.number"}{printf "%-15s %s\n",$1,$3}' grade.txt

name            s.number

列印輸出“what is your name?" 利用getline函數從終端接收輸入,并傳送給name變量,直到使用者輸入回車為止,如果第一域比對employees2中的記錄。

列印“found ",name變量,"on line" ,行号。

列印“see ya, ”,name變量

以上是傳入name變量的值存在于employees2中的情況

$ awk 'begin{printf "what is your name?" ;\

getline name < "/dev/tty"}\

$1 ~ name {print "found " name " on line ",nr "."}\

end{print "see ya, " name "."}' employees2

what is your name?tom

found tom on line 1.

see ya, tom.

不存在于employees2中的情況

what is your name?czm

see ya, czm.

參考至:《unix® shells by example fourth edition》by ellie quigley 

                  《linux與unix shell程式設計指南》

                 http://blog.sina.com.cn/s/blog_45b28bfb0100o0fs.html

本文為原創文章,轉載請注明出處、作者

如有錯誤,歡迎指正

郵箱: [email protected]

作者:czmmiao  文章出處:http://czmmiao.iteye.com/blog/1885280