首頁 >php教程 >PHP开发 >awk命令詳解

awk命令詳解

高洛峰
高洛峰原創
2016-12-15 11:06:381474瀏覽

一、前言

awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk。 awk語言最基本的功能是在檔案或字串中基於指定規則來分解抽取訊息,也可以基於指定的規則來輸出資料。完整的awk腳本通常用來格式化文字檔中的資訊。

二、基本語法

awk [opion] 'awk_script' input_file1 [input_file2 ...]

awk的常用選項option有:

① -F fs : 使用作為輸入記錄的字段分隔符,如果省略記錄的字段分隔符此選項,awk使用環境變數IFS的值

② -f filename : 從檔案filename讀取awk_script

③ -v var=value : 為awk_script設定變數

awk有三種運作方式:

,把awk的腳本指令直接放在指令中。

第二種,把awk的所有的腳本命令放在一個腳本檔案中,然後用-f選項來指定要運行的腳本命令檔。

第三種,將awk_script放入腳本檔案並以 #!/bin/awk -f 作為首行,給予該腳本可執行權限,然後在shell下透過鍵入該腳本的腳本名稱呼叫之。

三、awk腳本

awk腳本可以由一條或多條awk_cmd組成,對於多個awk_cmd,一個awk_cmd完成後,應該另起一行,以便進行隔。 

awk_cmd由兩個部分組成: awk_pattern { actions }。

另外,在awk指令中直接使用awk_script時,awk_script也可以被分成多行書寫,但必須確保整個awk_script被單引號括起來。

awk指令的一般形式:

awk ' BEGIN { actions }

awk_pattern1 { actions }

............

awk_patternN actionss; ' inputfile

其中BEGIN { actions } 和END { actions } 是可選的。

在awk腳本中可以使用AWK本身內建變量,如下: 

ARGC 命令列變元個數

ARGV 命令行變元數組

FILENAME 目前輸入FS 輸入域分隔符,預設為一個空格

RS 輸入記錄分隔符

NF 目前記錄裡域個數

NR 到目前為止記錄數

OFS 輸出域分隔符

ORS 輸出記錄符號記錄符號awk腳本的運行過程:

① 如果BEGIN 區塊存在,awk執行它指定的actions。

② awk從輸入檔中讀取一行,稱為一筆輸入記錄。 (如果輸入檔省略,將從標準輸入讀取)

③ awk將讀入的記錄分割成字段,將第1個字段放入變數$1中,第2個字段放入$2,以此類推。 $0表示整筆記錄。欄位分隔符號使用shell環境變數IFS或由參數指定。

④ 把目前輸入記錄依序與每一個awk_cmd中awk_pattern比較,看是否匹配,如果相匹配,就執行對應的actions。如果不匹配,就跳過對應的actions,直到比較完所有的awk_cmd。

⑤ 當一條輸入記錄比較了所有的awk_cmd後,awk讀取輸入的下一行,繼續重複步驟③和④,這個過程一直持續,直到awk讀取到文件尾。

⑥ 當awk讀完所有的輸入行後,如果存在END,就執行對應的actions。

1)input_file可以是多於一個檔案的檔案列表,awk將依序處理列表中的每個檔案。

2)一條awk_cmd的awk_pattern可以省略,省略時不對輸入記錄進行匹配比較就執行對應的actions。一條awk_cmd的actions 也可以省略,省略時預設的動作為列印目前輸入記錄,即{print $0} 。一條awk_cmd中的awk_pattern和actions不能同時省略。

3) BEGIN區塊和END區塊別位於awk_script的開頭和結尾。 awk_script中只有END區塊或只有BEGIN區塊是被允許的。如果awk_script只有BEGIN { actions } ,awk不會讀取input_file。

4) awk把輸入檔案的資料讀入內存,然後操作內存中的輸入資料副本,awk不會修改輸入檔的內容。

5) awk的總是輸出到標準輸出,如果想讓awk輸出到文件,可以使用重定向。

3.1.awk_pattern

awk_pattern模式部分決定actions動作部分何時觸發及觸發actions。

awk_pattern可以是以下幾種類型:

1) 正規表示式用作awk_pattern: /regexp/

注意,正則表達式regexp必須被/包起來

awk中正則表達式匹配操作中經常用到匹配操作中經常用到匹配操作的字符:

^ $ . [] | () * // :通用的regexp元字符

+ : 匹配其前的單個字符一次以上,是awk自有的元字符,不適用於grep或sed等

? : 匹配其前的單個字符1次或0次,是awk自有的元字符,不適用於grep或sed等

關於正則表達式的更多內容請參《正則表達式》

舉例:

awk '/ *$0.[0-9][0-9].*/' input_file

比如,行內容為$0.99. helllo的行就可以和上面的正規表示式相匹配

2)布林表達式用作awk_pattern,表達式成立時,觸發對應的actions執行。

① 表達式中可以使用變數(如欄位變數$1,$2等)和/regexp/

② 布林表達式中的運算元:

關係運算子: = == !=

​​符合運算子: value ~ /regexp/ 如果value符合/regexp/,則傳回真

value !~ /regexp/ 如果value不符/regexpvalue /,則回傳真

舉例: awk '$2 > 10 {print "ok"}' input_file

awk '$3 ~ /^d/ {print "ok"}' input_file

③ &&() 和|| (或) 可以連接兩個/regexp/或布林表達式,構成混合表達式。 !(非) 可以用於布林表達式或/regexp/之前。

舉例: awk '($1 10) {print $0 "ok"}' input_file

awk '/^d/ || /x$/ {print $0 "ok"}' input_ffile

④ 其它表達式用作awk_script,如賦值表達式等

舉例:

 awk '(tot+=$6); END{print "total points :" tot }' input_file // 分號不能省略

tot+=$6 {print $0} END{print "total points :" tot }' input_file // 與上面等效

當使用賦值表達式時,表示如果賦值後的變數是數字的話,如果為非0,就匹配,否則不匹配;如果為字串的話,非空就為匹配,否則不匹配。


awk內建字串函數:

gsub(r,s)           在整個$0中以s取代r

awk 'gsub(/name/,"x0 (r,s,t)         在整個t中用s取代r

index(s,t)          返回s中字串t的第一個位置

awk 'BEGIN {print index("Sunny","ny") }' temp     回傳4

length(s)           返回s的長度

match(s,r)         s$1s 是否包含匹配r的字串是否為符合"u")}' temp    回傳4

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

awk 'BEGIN {print split("12#345#6789",myarray,"#") {print split("12#345#6789",myarray,"#") "'

回傳3,同時myarray[1]="12", myarray[2]="345", myarray[3]="6789"

sprint(fmt,exp)     返回經fmt格式化後的exp

sub(r,s)   從$0中最左邊最長的子字串中用s代替r(只更換第一遇到的匹配字串)

substr(s,p)         返回字串s中從p開始的後綴部分

substr(s,p,n)       返回字串s中從p開始長度為n的後綴部分

awk字串連接操作 

[chengmo@centos5 ~]$ awk字串連接運算"a";b="b";c=(a""b);print c}'      

ab 

2.7.     printf函數的使用:

字元轉換: echo "65" |awk '{printf" %cn",$0}'    輸出A

 awk 'BEGIN {printf "%fn",999}'        輸出999.000000

}格式化:awk '{printf將第一個域全部左對齊顯示

2.8.     其他awk用法:

    向一行awk指令傳值:

awk '{if ($5

who |

awk '{if ($5

who | awkuser ' " are in " $2 ' user=$LOGNAME 使用環境變數

awk腳本指令:

開頭使用!/bin/awk -f  ,如果沒有這句話自含腳本將不能執行,範例:

!/bin /awk -f

# all comment lines must start with a hash '#'

# name: student_tot.awk

# to call: student_tot.awk grade.point

# to call: student_tot.awk grade.point

# print a header first

BEGIN

{

print "Student    Date   Member No.  Grade  Age  anced  Max" ====== ==============================================="

}

# let's add the scores of points gained

(tot+=$6);

# finished processing now let's print the total and average point 🜆

🜎 " tot

    print "Average Club Student points :" tot/N

}

2.9.     awk數組:

k 'BEGIN {record="123#456#789";split(record,myarray,"#")} 

END { for (i in myarray) {print myarray[i]} }

3.0 10kk一.條件判斷語句(if)


if(表達式) #if ( Variable in Array )

語句1

else

語句2個語句

中"如果你為了方便Unix awk判斷也方便你自已閱讀,你最好將多個語句用{}括起來。 Unix awk分枝結構允許嵌套,其格式為:


if(表達式)


{語句1}


elsechen if(表達式)

語句

@localhost nginx]# awk 'BEGIN{ 

test=100;

if(test>90)

{

    print "非常 good"

} print "good";

}

else

{

    print "no pass";

}

}'

每條指令語句後面可以用「;」號結尾。

 

二.循環語句(while,for,do)

1.while語句

while(表達式)


{語句}


例子:


[chengmo@localhost nginx]# awk 'BEGIN{ 

test=100;

total=0;

while(i{


    total+=i;

    i++;

}

print total;

}'


5050%

格式1:


for(變數in 陣列)

{語句}

for(k in ENVIRON)

{

    print k"="ENVIRON[k];

}

}'

SS =/ usr/libexec/openssh/gnome-ssh-askpass


SELINUX_LEVEL_REQUESTED=

SELINUX_ROLE_REQUESTED=

LANG=zh_CN.GB2312

。 。 。 。 。 。


說明:ENVIRON 是awk常數,是子典型陣列。


格式2:


for(變數;條件;表達式)


chen

mo@localhost nginx]# awk 'BEGIN{ 

total=0;

for(i=0;i{

    total+=i;

}


print total;

}'

5050

3.do循環

格式:

do

}


[chengmo@localhost nginx] # awk 'BEGIN{ 

total=0;


i=0;

do

{

    total+=i;

)


}'

5050


 

以上為awk流程控制語句,從語法上面大家可以看到,與c語言是一樣的。有了這些語句,其實很多shell程式都可以交給awk,而且效能是非常快的。

break 當 break 語句用於 while 或 for 語句時,導致退出程式循環。 

continue 當 continue 語句用於 while 或 for 語句時,將程式循環移到下一個迭代。 

next 能導致讀入下一個輸入行,並回到腳本的頂部。這可以避免對目前輸入行執行其他的操作過程。 

exit 語句使主輸入循環退出並將控制權轉移到END,如果END存在的話。如果沒有定義END規則,或在END中套用exit語句,則終止腳本的執行。 


NR與FNR:

QUOTE:

A. awk對多重輸入檔案的執行順序是,先將程式碼作用於第一個檔案(一行行讀入),然後該重複的程式碼再作用於第二個文件,再作用於第三個檔案。

B. awk對多輸入檔的執行順序產生了行序號的問題。當第一個文件執行完,下次讀完第二個文件,那麼第二個文件的第一行怎麼算呢?如果又算為1的話,那不就兩個1了麼? (因為第一個文件也有第一行)。這就是NR和FNR的問題。

   NR :全域行數(第二個檔案的第一行接著第一個檔案尾行數順序計數)


   FNR:目前檔案本身的行數(不考慮前幾個輸入檔案的自身行數及總數)

         例如:data1.txt中有40行,data2.txt中有50行,那麼awk '{}' data1.txt data2.

  42…90

                   FNR的值依序為:1,2…40,1, 2…50 

getline0如果使用者有一個資料記錄類似兩個實體記錄,那麼getline將尤其有用。它完成一般字段的分離(設定字段變數$0 FNR NF NR)。如果成功則回傳1,失敗則回傳0(到達檔案尾)。


QUOTE:

A. getline從整體來說,應這麼理解它的用法:

            當其左右無重定向符 | 或

            var 或$0(無變數);應該注意到,由於awk在處理getline之前已經讀入了一行,所以getline得到

            的返回結果是隔行的。

            當其左右有重定向符| 或

        get  line

        get   文件的第一行,而不是隔行。

B. getline用法大致可分為三大類(每大類又分兩小類),即總共有6種用法。程式碼如下:

QUOTE:

nawk 'BEGIN{“cat data.txt”|getline d; print d}' data2.txt 

nawk 'BEGIN{“cat data.txt”|getline; print $0}' data2 .txt

nawk 'BEGIN{getline d

nawk 'BEGIN{getline

.程式碼皆實作「只列印data.txt檔案的第一行」(若列印全部行,用循環)

eg. nawk 'BEGIN{FS=”:”;while(getline0 ){print $1}}' data.txt

QUOTE:

nawk '{getline d; print d”#”$3}' data.txt

 awkk ,然後把下一行指定給變數d,再先列印d,由於d後面有換行符,所以後面緊跟的#會覆蓋d,後面的$3同樣也會覆蓋d。

QUOTE:

nawk '{getline; print $0”#”$3}' data.txt

awk先讀入第一行接著處理getline函數,然後把下一行指定給$0,現在的$0已經是下一行內容,後面的#和$3(從$0取)會覆蓋$0的內容。

在awk中,有時需要呼叫系統工具來完成awk不擅長的工作,awk提供的system指令可以用來執行,但收不到外部工具的輸出結果。還好可以運用getline來滿足這個需求。例如

test.awk:

{

   datecommand="/bin/date -j -f "%d/%b/%Y:%H:%M:%S" " $olddatestr ""+%Y %m%d %H%M%S"";

   datecommand | getline newdatestr 

   close(datecommand);

}

有上限,而且不大(比如說16),所以最後做一個close是好習慣。把指令串定義為變數也是為了close的時候方便



更多awk指令詳解 相關文章請關注PHP中文網!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn