awk 字串處理

G8bao7發表於2015-05-11
from: http://czmmiao.iteye.com/blog/1885280

awk內建字串函式

函式 說明
gsub( Ere, Repl, [ In ] ) 除了正規表示式所有具體值被替代這點,它和 sub 函式完全一樣地執行,。
sub( Ere, Repl, [ In ] ) 用 Repl 引數指定的字串替換 In 引數指定的字串中的由 Ere 引數指定的擴充套件正規表示式的第一個具體值。sub 函式返回替換的數量。出現在 Repl 引數指定的字串中的 &(和符號)由 In 引數指定的與 Ere 引數的指定的擴充套件正規表示式匹配的字串替換。如果未指定 In 引數,預設值是整個記錄($0 記錄變數)。
index( String1, String2 ) 在由 String1 引數指定的字串(其中有出現 String2 指定的引數)中,返回位置,從 1 開始編號。如果 String2 引數不在 String1 引數中出現,則返回 0(零)。
length [(String)] 返回 String 引數指定的字串的長度(字元形式)。如果未給出 String 引數,則返回整個記錄的長度($0 記錄變數)。
substr( String, M, [ N ] ) 返回具有 N 引數指定的字元數量子串。子串從 String 引數指定的字串取得,其字元以 M 引數指定的位置開始。M 引數指定為將 String 引數中的第一個字元作為編號 1。如果未指定 N 引數,則子串的長度將是 M 引數指定的位置到 String 引數的末尾 的長度。
match( String, Ere ) 在 String 引數指定的字串(Ere 引數指定的擴充套件正規表示式出現在其中)中返回位置(字元形式),從 1 開始編號,或如果 Ere 引數不出現,則返回 0(零)。RSTART 特殊變數設定為返回值。RLENGTH 特殊變數設定為匹配的字串的長度,或如果未找到任何匹配,則設定為 -1(負一)。
split( String, A, [Ere] ) 將 String 引數指定的引數分割為陣列元素 A[1], A[2], . . ., A[n],並返回 n 變數的值。此分隔可以透過 Ere 引數指定的擴充套件正規表示式進行,或用當前欄位分隔符(FS 特殊變數)來進行(如果沒有給出 Ere 引數)。除非上下文指明特定的元素還應具有一個數字值,否則 A 陣列中的元素用字串值來建立。
tolower( String ) 返回 String 引數指定的字串,字串中每個大寫字元將更改為小寫。大寫和小寫的對映由當前語言環境的 LC_CTYPE 範疇定義。
toupper( String ) 返回 String 引數指定的字串,字串中每個小寫字元將更改為大寫。大寫和小寫的對映由當前語言環境的 LC_CTYPE 範疇定義。
sprintf(Format, Expr, Expr, . . . ) 根據 Format 引數指定的 printf 子例程格式字串來格式化 Expr 引數指定的表示式並返回最後生成的字串。



gsub(r,s) 在整個$0中用s替代r;gsub(r,s,t) 在整個t中用s替代r;  類似於sed查詢和替換。它允許替換一個字串或字元為另一個字串或字元,並以正規表示式的形式執行。第一個函式作用於記錄$0,第二個gsub函式允許指定目標,然而,如果未指定目標,預設為$0。

index(s,t):函式返回目標字串s中查詢字串t的首位置。
length(s) :返回s長度
match(s,r): 測試s是否包含匹配r的字串
split(s,a,fs) 在fs上將s分成序列a,使用域分隔符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定義的匹配。



1.gsub
 
sub(/^[[:blank:]]*/,"",變數)  是去掉變數左邊的空白符
sub(/[[:blank:]]*$/,"",變數) 是去掉變數右邊的空白符
gsub(/[[:blank:]]*/,"",變數) 是去掉變數中所有的空白符
 

在整個記錄中替換一個字串為另一個,使用正規表示式格式, /目標模式/,替換模式/。例如改變學生序號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/)}'
0
# awk 'BEGIN{print match("ANCD",/D/)}'
4
# awk '$1=="J.Lulu" {print match($1,"u")}' grade.txt
4
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,"#")}'                    
3
這個例子中,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
M.Tans 5/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 29
P.Bunny 02/99 48 Yellow 12 35 28
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,只返回其副檔名。
# STR="mydoc.txt"
# 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

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}'
A
所有的字元轉換都是一樣的,下面的例子表示進行浮點數轉換後'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
M.Tans          48311
J.Lulu          48317
P.Bunny         48
J.Troll         4842
L.Tansl         4712
列印輸出“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中的情況
$ 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?czm
See ya, czm.

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26250550/viewspace-1648012/,如需轉載,請註明出處,否則將追究法律責任。

相關文章