awk

在linux中有文本三劍客:grep、sed、awk,grep和sed之前已經給大家介紹過了,接下來給大家介紹awk這個強大工具的使用。

一、awk簡介

   awk:Aho, Weinberger, Kernighan報表生成器或報告生成器,格式化文本輸出。awk經過改進生成的新的版本nawk,gawk,現在默認linux系統下日常使用的是gawk,用命令可以查看正在應用的awk的來源(ls -l /bin/awk )。

二、使用方法

基本用法:

awk [options] ‘program’ var=value file…
awk [options] -f programfile var=value file…
awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file ...
        program:PATTERN{action statements}

注意:語句之間用分號分隔。
分隔符、域和記錄:

由分隔符分隔的字段標記$1,$2...$n稱爲域表示。$0表示所有域。
文件的每一行稱爲記錄。

選項:

    -F 指明輸入時用到的字段分隔符
    -v var=value:自定義變量

gawk工作原理:

第一步:執行BEGIN{action;… }語句塊中的語句。BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中。

第二步:從文件或標準輸入(stdin)讀取一行,然後執行pattern{ action;… }語句塊,它逐行掃描文件,從第一行到最後一行重複這個過程,直到文件全部被讀取完畢。如果沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊。

第三步:當讀至輸入流末尾時,執行END{action;…}語句塊。END語句塊在awk從輸入流中讀取完所有的行之後即被執行,比如打印所有行的分析結果這類信息彙總都是在END語句塊中完成,它也是一個可選語句塊。

1、print

    print item1,item2
  注意事項:
  (1)逗號分隔符; 
  (2)輸出的各item可以字符串,可以是數值;當前記錄的字段(域)、變量或awk的表達式; 
  (3)變量替換不能用引號引起來; 
  (4)如果省略item,相當於print $0,$0爲所有域。

注意:此處的$符含義與shell中變量不同。

2、變量

  自定義變量
    -v var=value
  內建變量
     FS :input field seperator,默認爲空白字符;

示例:

[root@localhost~]#awk -v FS=':' '{print $1,$3}' /etc/passwd
[root@localhost~]#awk -v FS=':' '{print $1FS$3}' /etc/passwd
[root@localhost~]#seg=":";awk -v FS=$seg '{print $1FS$3}' /etc/passwd

 OFS:output field seperator,默認爲空白字符

[root@localhost~]#awk -v FS=":" -v OFS="#####" '{print $1,$3}' /etc/passwd

RS:指明輸入的換行分隔符

[root@localhost~]#awk -v RS=" " '{print}' /etc/passwd

ORS:輸出時的換行符

[root@localhost~]#awk -v RS=' ' -v ORS="####" '{print}' /etc/passwd

NF:number of field ,字段的數量

[root@localhost~]#awk -F: '{print $(NF-2)}' /etc/passwd

NR:number of record,行數;

[root@localhost~]#awk '{print NR}' /etc/passwd

FNR:單多個文件單獨計數。

[root@localhost~]#awk '{print FNR}' /etc/passwd /etc/shadow

FILENAME:文件名

[root@localhost~]#awk '{print FILENAME,$1,$3}' /etc/passwd

ARGC:命令行參數的個數

[root@localhost~]#awk '{print ARGC}' /etc/passwd /etc/inittab
注意:命令行參數個數,除action其餘都算參數。

ARGV:數組,保存的是命令行所給定的參數的名稱

可以把program寫入一個文件中調用

[root@localhost~]#cat awkscript
{print script,$1,$2}
[root@localhost~]#awk -F: -f awkscript script=“awk” /etc/passwd
數字和變量,不需要加引號,字符串需要引號

注意,顯示內部變量不需要加“$”。變量名區分字符的大小寫。

3、printf命令

    格式化輸出:printf FROMAT,item1,item2...
注意事項:
(1)FORMAT必須要給出;
(2)不會自動換行,需要顯示給出換行控制符,\n;
(3)FORMAT中需要分別爲後面的每個item指定一個格式化符號;

格式符:
    %c:顯示字符的ASCLL碼
    %d,%i:顯示十進制整數
    %e,%E:科學計數法顯示;
    %f:顯示爲浮點數
    %g,%G:以科學計數法或浮點形式顯示數值;
    %s:顯示字符串
    %u:無符號整數
    %%:顯示%自身

[root@localhost~]#awk -F : '{printf "%s\n" $1}' /etc/fstab

修飾符:
    #[.#]:第一個數字控制顯示的寬度;第二個#表示小數點後的精度; 
        %3.1f 
    -:左對齊,默認右對齊

[root@localhost~]#awk -F: '{printf "usrname:%-15s uid:%-20d\n",$1,$3}' /etc/passwd

    +:顯示數值的符號
操作符:
    算數操作符:+ - * / ^ % 
    字符串操作符:沒有符號的操作符,字符串鏈接
    賦值操作符:
        = += -= *= 
    比較操作符:
        > >= < <= != ==
模式匹配符:
    ~
    !~:是否不匹配
邏輯操作符:
    && || !
函數調用:

[root@localhost~]#awk -F: '$0~/root/{print $0}' /etc/passwd
[root@localhost~]#awk -F: '$0 !~ /root/{print $0}' /etc/passwd
[root@localhost~]#awk -F: '$3>50 && $3<500{print $1,$3}' /etc/passwd
[root@localhost~]#awk -F: '!($3==0){print $1,$3}' /etc/passwd

[root@localhost~]#awk -F: '$3 != 0{print $1,$3}' /etc/passwd
function_name(argu1,argu2,…)

條件表達式(三目表達式):
    selector?if-true-expression:if-false-expression

[root@localhost~]#awk -F: '{$3>=500?type="com":type="system";printf "%-15s %20s\n",$1,type}' /etc/passwd

PATTERN

(1)如果爲指定:空模式,匹配每一行;
(2)/regular expression/:僅處理能夠匹配到的行;
(3)relational expression:關係表達式,結果爲真才能被處理。

注意:不支持直接給出數字的格式
[root@localhost~]#awk -F: '/^root/{print $0}' /etc/passwd
區分:
[root@localhost~]#awk -F: 'i=1{print i,$0}' test
[root@localhost~]#awk -F: 'i=0{print i,$0}' test
這裏寫圖片描述

上述情況中i在前面起到一個判斷作用,如果i=0爲假不執行後面語句,如果i=1或任何其他數都執行後面語句。
真:結果爲非0值,非空字符串
假:結果爲空字符串或0值

這裏寫圖片描述
取奇數和偶數
這裏寫圖片描述

BEGIN/END模式

    BEGIN{}:僅在開始處理文件中的文本之前執行一次;
    END{}:僅在文本處理完成之後執行一次;

[root@localhost~]#awk -F: 'BEGIN{print "name uid\n------------------------"}{printf "%-15s %20\n",$1,$3}END{print "===============================\n"}' /etc/passwd
這裏寫圖片描述

常用的action

    expression:算數,比較表達式等
    control statements:if,while等;
    compound statement:組合語句;    
    input statements
    output statements

控制語句

    if(condition){statements}
    if (condition) {statements} else {statements}
    while (condition){statements}
    do {statements} while(condition)
    for (expr1;expr2;expr3){statements}
    break
    continue
    delete array[index]
    delete array 
    exit
    { statements }

if-else

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

[root@localhost~]#awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd
[root@localhost~]#awk -F: '{if($3>=1000) {printf "common user:%s\n",$1} else{ print"root or sysuser:%s\n",$1}}' /etc/passwd
使用場景:對awk取得的整行或某個字段做條件判斷;

[root@localhost~]#awk -F: '{if($NF==/bin/bash) print $1}' /etc/passwd
[root@localhost~]#awk '{if(NF>5) print $0}' /etc/passwd
[root@localhost~]#df -h |awk -F[%] '/^\dev/{print $1}' |awk '{if($NF>=20) print $1}'

    while循環
    語法:while(condition)statement
        條件真,進入循環;條件假,退出循環
    使用場景:對一行內的多個字段逐一類似處理時使用;對數組中的各元素逐一處理時使用;
        length()

[root@localhost~]#awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i);i++}}' /etc/grub2.cfg
[root@localhost~]#awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if length($i>=7){print $i,length($i)} ;i++}}' /etc/grub2.cfg

這裏寫圖片描述
do-while循環
語法:do statement while(condition)
意義:至少執行一次循環體

    for循環
    語法:for(expr1;expr2;expr3) statement
        for(variable assignment;condition;iteration process){for-body}

[root@localhost~]#awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
特殊用法:能夠遍歷數組中的每一個元素
語法:for (var in array){for-body}

    switch語句
    語法:switch(expression){case CALUE1 or /regexp/:statement;case or /regexp2/:statement;...;default:statement}

    break和continue
    break [n]

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

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

array數組
    關聯數組:array[index-expression]
        index-expression
            可使用任意字符串,字符串要使用雙引號
            如果某數組元素事先不存在,在引用時,awk會自動創建此元素,並將其值初始化爲“空串”
    若要判斷數組中是否存在某元素,要使用“index in array”格式進行

[root@localhost~]#awk'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";print weekdays["tue"]}'

    若要遍歷數組中的每個元素,要使用for循環
    for(variable in array)

注意:var會遍歷array的每個索引;

[root@localhost~]#nestat -tan |awk '/^tcp\>/{state [$NF]++}END{for(in state){print i,state(i)}}}'
[root@localhost~]#awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}}' /var/log/httpd/access_log

練習:1統計/etc/fstab文件中每個文件系統出現的次數

[root@localhost~]#awk '{filetype[$3]++}END{for (i in filetype) {print i,filetype[i]}}' /etc/fstab
2統計每個單詞
[root@localhost~]#awk '{for(i;i<=NF;i++){count[$i]++}}END{for(i in count){print i,count[i]}}' /etc/fstab
3取ip地址
[root@localhost~]#ifconfig eth0 |awk -F"[ :]+" '(NR==2) {print $4}'

函數

數值處理:rand():返回0和1之間一個隨機數

[root@localhost~]#awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
字符串處理:

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

sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並將第一個匹配的內容替換爲s

[root@localhost~]#echo "2008:08:08 08:08:08" | awk 'sub(/:/,“-",$1)'

gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並全部替換爲s所表示的內容

[root@localhost~]#echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,“-",$0)'

split(s,array,[r]):以r爲分隔符,切割字符串s,並將切割後的結果保存至array所表示的數組中,第一個索引值爲1,第二個索引值爲2,…

[root@localhost~]#netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++} END{for (i in count) {print i,count[i]}}'

system命令

空格是awk中的字符串連接符,如果system中需要使用awk中的變量可以使用空格分隔,或者說除了awk的變量外其他一律用""引用起來。

[root@localhost~]#awk BEGIN'{system("hostname") }'

[root@localhost~]#awk 'BEGIN{score=100; system("echo your score is " score) }'

注意有空格

[root@localhost~]#str=hello,awk;awk -v hi=$str 'BEGIN{system("echo" hi)}'

awk腳本

將awk程序寫成腳本,直接調用或執行

示例:

[root@localhost~]#vim f2.awk
#!/bin/awk –f
#this is a awk script {if($3>=1000)print $1,$3}
[root@localhost~]#chmod +x f2.awk
[root@localhost~]#f2.awk –F: /etc/passwd

向awk腳本傳遞參數

格式:

awkfile var=value var2=value2... Inputfile

注意:在BEGIN過程中不可用。直到首行輸入完成以後,變量纔可用。可以通過-v 參數,讓awk在執行BEGIN之前得到變量的值。命令行中每一個指定的變量都需要一個-v參數。

示例:

[root@localhost~]#cat test.awk
#!/bin/awk –f
{if($3 >=min && $3<=max)print $1,$3}

[root@localhost~]#chmod +x test.awk
[root@localhost~]#test.awk -F: min=100 max=200 /etc/passwd

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