awk

awk命令:

Linux文本處理三劍客:

grep, egrep, fgrep: 文本過濾器

sed: 行編輯器

模式空間,保持空間

awk: 報表生成器,格式化文本輸出

 

AWKa.k.a Aho, Weinberger, Kernighan

將文件的一行讀入,並將其分隔爲多段,用$1..位置變量表示,$0表示全部段

GNU awk = gawk

 

基本用法:

gawk [options] 'program' file file ...

program: PATTERN { ACTION STATEMENT }

PATTERN省略表示對整個文件的每行文本執行後面的操作,由語句組成,語句分隔符是;

 

ACTION: print, printf

 

選項:

-F[]:指明輸入字段分隔符;

-v var_name=value: 變量賦值

 

例: gawk -F: '{print $1,$3}' /etc/passwd

 

1awk的輸出命令print

 

print item1, item2, ...

要點:

(1) item間使用逗號分隔,而輸出時則使用輸出分隔符分隔;

(2) 輸出的各item可以字符串或數值、當前記錄的字段($n)、變量或awk的表達式;數值會被隱式轉換爲字符進行輸出;

(3) print後面的item如果省略,相當於print $0;  輸出“空白”,使用print "";

 

2、變量                        

2.1 內置變量

FS input field seperator輸入字段分隔符默認爲空白字符;

wKiom1VUpaiRNd8KAABOuJ4L3Ts850.jpg

RSinput record separator, 輸入行分隔符默認爲換行符;

例:awk -v RS=[" "/] '{pirint $0}' /etc/passwd

表示輸出/etc/passwd文件,換行符爲空白或/

OFS output field seperator字段分隔符默認爲空白字符;默認爲空白字符;

wKioL1VUpzWzjZNeAABhCPZI8vg084.jpg

ORSoutput record separator,行分隔符默認爲換行符;

例:把用戶名輸出爲一行

wKiom1VUpc6RQIGBAADuZU504HE536.jpg

NF: number of field in current record當前行的字段數;

wKioL1VUp2HiDF6sAABzD6BQoIs777.jpg

NR行數,所有文件統一計數;

wKiom1VUpfqg3V_iAABxN72wApw373.jpg

FNR行數,各文件分別計數;

wKioL1VUp4eC0pQfAACDc6uVKyg411.jpg

FILENAME:當前文件名;

 

ARGC:命令行參數的個數;

例:awk '{print ARGC}' /etc/passwd

>2

awk '{print ARGC}' /etc/passwd /etc/issue

>3

ARGV:數組,保存了命令行參數;

例:

[root@MYPC ~]# awk '{print ARGV[0]}' /etc/issue

awk

[root@MYPC ~]# awk '{print ARGV[1]}' /etc/issue

/etc/issue

 

2.2 自定義變量

定義變量的位置:

(1) 可以program中定義變量;

(2) 通過-v選項定義變量;

變量名區分字符大小寫

wKioL1VUp57xQVBEAAB48YbHHNA030.jpg

 wKioL1VUp7iR7pinAABtcoDXjcc729.jpg 

3printf命令

 

格式: printf format, item1, item2, ...

 

要點:

(1) format是必須的;

(2) 不會自動換行,需顯式給定行分隔符\n

(3) format中需要分別爲後面的每個item指定一個格式符;

 

格式符:都以%開頭,後跟一個字符

%c: 顯示字符的ASCII碼;

%d%i: 顯示十進制整數;

wKiom1VUpk_wQs6CAAApaophEx8826.jpg

 

wKioL1VUp_DAhMIBAAA-ZfNP7hs774.jpg

%e, %E: 科學計數法顯示數值;

%f: 顯示爲浮點數;

%g, %G: 以科學計數法格式或浮點數格式顯示數值;

%s: 字符串

%u: 無符號的整數

%%: 顯示%自身

 

修飾符:

#[.#]: 第一個#指定顯示寬度,例如%30s表示用30個字符長度去顯示後面的字符串;第二個#表示小數點後的精度;

wKiom1VUpouxpnO4AAA2QMcYMZo540.jpg

 

wKioL1VUqBiQ67fUAABXJvjJko4387.jpg

- 左對齊

wKiom1VUpq_TEb50AABZbuSkzgc346.jpg

+:顯示數值正負符號

 

4、操作符:

算術操作符:

x+y, x-y, x*y, x/y, x^y, x%y

-x: 負值

+x: 轉換爲數值

 

字符串操作:字符串連接

 

賦值操作符:

= += -= *=,  /=,  %=, ^=

++, --

 

比較操作符:

>, >=, <. <=, ==, !=

 

模式匹配符:

~

!~

 

邏輯操作符:

&&

||

 

條件表達式:

selector?if-true-expression:if-false-expression

 

例:# awk -F: '{$3>=500?usertype="common user":usertype="sysuser or admin";printf "%20s:%-s\n",$1,usertype}' /etc/passwd

 

函數調用:

function_name(argu1,argu2,...)

 

5PATTERN

 

(1) /regular expression/: 僅處理能夠被/regular expression/所匹配到的行;

wKioL1VUqDvBkx_tAAB3M-68sK4456.jpg

(2) relational expression:關係表達式,有真假之分,一般來說,其結果爲非0或非空字符串時爲“真”,否則,爲“假”;

wKiom1VUps_wCcNvAACfMWiDKmk683.jpg

表示第6個字段符合後面的模式就輸出這一行

wKioL1VUqFmgoUBdAABq932SQzw497.jpg

(3) line ranges:行範圍,類似sedvim的地址定界法;startline, endlinestartline和endline使用的是模式表達式

wKiom1VUpvaCG7YaAABkJdTjV1Q372.jpg

(4) BEGIN/END: 特殊模式

僅在awk運行程序之前執行一次(BEGIN)或僅在awk運行程序之後執行一次(END);

如果只是顯示/etc/passwd的賬戶和賬戶對應的shell,而賬戶與shell之間以逗號分割,而且在所有行添加列名name,shell,在最後一行添加"blue,/bin/nosh"

cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'

name,shell

root,/bin/bash

daemon,/bin/sh

bin,/bin/sh

sys,/bin/sh

....

blue,/bin/nosh

 

awk工作流程是這樣的:先執行BEGING,然後讀取文件,讀入有/n換行符分割的一條記錄,然後將記錄按指定的域分隔符劃分域,填充域,$0則表示所有域,$1表示第一個域,$n表示第n個域,隨後開始執行模式所對應的動作action。接着開始讀入第二條記錄······直到所有的記錄都讀完,最後執行END操作。

 

(5) empty: 空模式,匹配任意行;

 

 

6、常用的action

 

(1) Expressions 表達式

(2) Control statements 控制語句,如if

(3) Compound statements 複合語句

(4) input statements 輸入語句

(5) output statements 輸出語句

 

7、控制語句

 

if (condition) statement [ else statement ]

while (condition) statement

do statement while (condition)

for (expr1; expr2; expr3) statement

for (var in array) statement

break

continue

delete array[index]

delete array

exit [ expression ]

{ statements }

 

7.1 if-else

 

語法:if (condition) statement [ else statement ]

if (condition) { statements; } [ else { statements; }]

 

# awk -F: '{if ($3>=500) {print $1," is a common user.";} }' /etc/passwd

# awk -F: '{if ($3>=500) {print $1," is a common user.";} else {print $1," is a system user or admin.";}}' /etc/passwd

# awk '{if (NF>6) print NF, $0 }' /etc/inittab

 

用法:對awk取得的整行或行中的字段做條件判斷;

 

7.2 while循環

語法:while (condition) statement

while (condition) { statements }

條件爲真時進行循環,直到爲假退出;

 

用法:通常用於在當前行的各字段間進行循環;

 

# awk '{i=1;while(i<=NF){printf "%20s:%d\n",$i,length($i); i++}}' /etc/inittab

# awk '{i=1;while(i<=NF){if(length($i)>4){print $i,length($i)}i++;}}' /etc/inittab             length是個內置獲取字符串長度的函數

 

7.3 do-while循環

語法:do statement while (condition)

do { do-while-body }  while (condition)

意義:至少執行一次循環體;

 

7.4 for循環

語法:for (expr1; expr2; expr3) statement

for (expr1; expr2; expr3) { statements }

 

for (varaiable assignment; condition; iteration process) { for-body }

 

# awk '{for(i=1;i<=NF;i++) {printf "%s:%d\n", $i, length($i)}}' /etc/inittab

 

for循環在awk中有一個專用於遍歷數組元素:

語法:for (var in array) { for-body }

{for(i in array){print aarray[$i]}}'

 

7.5 switch

語法:switch (expression) {case VALUE or /REGEXP/: statement; ...; default: statementN}

 

7.6 break and continue

break [n]: 退出當前循環

continue:提前結束本輪循環,直接進入下輪循環

 

7.7 next

提前結束對本行的處理而進入下一行的處理

 

取出UID爲偶數的用戶名和UID

#awk -F:'{if($3%2==0){print $1,$3;}}' /etc/passwd

# awk -F: '{if($3%2!=0) next;print $1,$3}' /etc/passwd

 

8Array

 

關聯數組:array[index-expression]

 

index-expression:

可以使用任意字符串;

如果某數組元素事先不存在,在引用時,awk會自動創建此元素並將其值初始化爲空串;

因此,若要判斷數組是否存在某元素,要使用“index in array”進行;

 

a[mon]="Monday"

print a[mon]

 

要遍歷數組中的每個元素,使用: for (var in array) { for body }

 

 注意:var會遍歷array的每一個索引,print array[var]

 

例:統計每一行中各單詞分別出現的次數

~]# awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]}}' awk.txt

 

~]# ss -tan | awk '!/^State/{state[$1]++}END{for (i in state) {print i,state[i]}}'

~]# netstat -tan | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}'

 

練習:統計httpd訪問日誌中,每個IP出現的次數;

~]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' /var/log/httpd/access_log

 

9、函數

 

9.1 內置函數

數值處理:

rand() 返回01之間一個隨機數;

 

字符串處理:

length([s]) 返回指定字符串的長度

sub(r, s [, t]):以r所表示的模式來查找t字符串中的匹配,將其第一次出現替換同s所表示的字符串;

sub(ab,AB,$0)

gsub(r, s [, t]):以r所表示的模式來查找t字符串中的匹配,將其所有的出現均替換同s所表示的字符串;

split(s, a [, r]): r爲分隔符切割字符串s,並將切割的結果保存至a表示數組中;返回字段的個數

 

~]# netstat -tan | awk '/^tcp/{len=split($5,client,":");ip[client[len-1]]++}END{for(i in ip){print i,ip[i]}}'

 

substr(s, i [, n]) s表示的字符串中取子串,從i開始,取n個字符;

 

時間類的函數:

systime(): 取時間戳;

 

位運算函數:

and(v1,va2):

 

9.2 自定義函數

function f_name(p,q)

{

...

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章