AWK命令----三劍客之一

一、AWK概念 
    awk 是一種編程語言,用於在linux/unix下對文本和數據進行處理。數據可以來自標準輸(stdin)、一個或多個文件,或其它命令的輸出。它在命令行中使用,但更多是作爲腳本來使用。awk有很多內建的功能,比如數組、函數等,這是它和C語言的相同之處,靈活性是awk最大的優勢。

二、AWK用法
   1、語法格式
        awk [options] 'scripts' var=value file(s)
        awk [options]  -f scriptfile var=value file(s)
   2、常用參數
        -F 指定分隔符(可以是字符串或正則表達式;如-F:)
        -f 從腳本文件中讀取awk命令
        -v var=value 賦值變量,將外部變量傳遞給awk
  3、內置變量 
       ARGC               命令行參數個數
       ARGV               命令行參數排列
       ENVIRON         支持隊列中系統環境變量的使用
       FILENAME       awk瀏覽的文件名
       FNR                 瀏覽文件的記錄數
       FS                   設置輸入域分隔符,等價於命令行 -F選項
       NF                   瀏覽記錄的域的個數,執行過程中對應於當前的字段數
       NR                  已讀的記錄數,相當於行號
       OFS                輸出域分隔符
       ORS                輸出記錄分隔符
       RS                  控制記錄分隔符
       $0變量是指整條記錄。$1表示當前行的第一個域,$2表示當前行的第二個域,......以此類推。
       $NF是number finally,表示最後一列的信息,跟變量NF是有區別的,變量NF統計的是每行列的總數
  4、常用參數
       -F 指定分隔符(可以是字符串或正則表達式)
       -f 從腳本文件中讀取awk命令
       -v var=value 賦值變量,將外部變量傳遞給awk
  5、AWK模式和操作
      模式
          /正則表達式/:使用通配符的擴展集
          關係表達式:使用運算符進行操作,可以是字符串或數字的比較測試
          模式匹配表達式:用運算符~(匹配)和!~(不匹配)
          BEGIN語句塊、pattern語句塊、END語句塊
      操作
          操作是由一個或多個命令、函數、表達式組成,之間由換行符或分號隔開,並位於大括號內,主要部分是:變量或數組賦值、輸出命令、內置函數、控制流語句
   6、AWK腳本基本結構
       awk 'BEGIN{ print "start" } pattern{ commads } END{ print "end" }' file

三、awk工作原理
    awk 'BEGIN{ commads } pattern{ commads } END{ commads }'
       第一步:執行BEGIN{ commads }語句塊的語句
       第二步:從文件或標準輸入(stdin)讀取一行,然後執行pattern{ commads }語句塊,它逐步掃描文件,從第一行到最後一行重複這個過程,直到文件全部被讀取完畢
       第三步:當讀至輸入流末尾時,執行END{ commads }語句塊

    BEGIN{ commads }語句塊  在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊
    END{ commads }語句塊 在awk從輸入流中讀取完所有的行之後即被執行,它也是一個可選語句塊
    pattern{ commads }語句塊 中的通用命令是最重要的部分,它也是可選的。如果沒有提供pattern語句塊,則默認執行{ print },即打印讀取到的每一行,awk讀取的每一行都會執行該語句塊

  示例

[root@os test]# awk '/root/' /etc/passwd  #默認是打印讀取到的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@os test]# awk -F: '/root/ { print $1,$NF }' /etc/passwd   #以:分隔,打印第一和最後一列
root /bin/bash
operator /sbin/nologin
[root@os test]# echo -e "a line \nb line" | awk 'BEGIN{ print "start" } { print } END{ print "end" }'
start
a line 
b line
end
#統計/etc/passwd文件中每行的字符數
[root@os test]# awk -F "" '{for(i=1;i<=NF;i++) if($i!="\n") ++sum;print sum;a=a+sum;sum=0}END{print "sum:"a}' /etc/passwd

四、外部變量、運算、判斷
    1、外部變量,藉助 -v選項,可以將外部值傳遞給awk

[root@os test]# var=10010
[root@os test]# echo | awk -v VARIABLE=$var '{ print VARIABLE }'
10010
[root@os test]# unset var   #撤消變量

    2、運算

類型 運算符 描述
算術運算符 + - 加,減
* / & 乘,除,求餘
+ - ! 一元加,減和邏輯非
^*** 求冪
++  -- 增加或減少,作爲前綴或後綴
賦值運算符 =、+=、-=、/=、%=、^=、**= 例:a+=5,等價於a=a+5,其它類同
邏輯運算符 ||、&&  邏輯或和邏輯與
關係運算符 <、<=、>、>=、!=、==  
正則運算符 ~、!~ 匹配正則和不匹配正則
其它運算符 條件表達式
$ 字段引用
in 數組中是否存在某鍵值

 








 

 

 

 

 

 

 

 

 

算術運算示例
[root@os test]# awk 'BEGIN{ a="b";print a++,++a}'
0 2
#注意:所有用作算術運算符進行操作,操作數自動轉爲數值,所有非操作數值變爲0
賦值運算示例
[root@os test]# awk 'BEGIN{ a=4;print a+=5}'
9
[root@os test]# awk 'BEGIN{ a=4;print a*=5}'
20
邏輯運算示例
[root@os test]# awk 'BEGIN{ a=4;b=3;print (a>5 && b<4),(a>5 || b<4)}'
0 1
關係運算示例
[root@os test]# awk 'BEGIN{ a=4;if(a<5){print "ok"}}'
ok
正則運算示例
[root@os test]# awk 'BEGIN{ a="100absfc";if(a ~ /^100/){print "ok"}}'
其它運算示例
[root@os test]# awk 'BEGIN{ a="b";arr[0]="b";arr[1]="c";print (a in arr)}'
0
[root@os test]# awk 'BEGIN{ a="b";arr[0]="b";arr["b"]="c";print (a in arr)}'
1
[root@os test]# awk 'BEGIN{ a=10;print a<9?"ok":"err"}' 
err

五、AWK高級輸入輸出
    1、讀取下一條記錄
       awk中next語句使用:在循環逐行匹配,如果遇到next,就會跳過當前行,直接忽略下面語句而進行下一行匹配。多用於多行合併
 

[root@os awktest]# vi test.txt 
a
b
c
d
e
[root@os awktest]# awk 'NR%2==1{next}{print NR,$0}' test.txt 
2 b
4 d

[root@os awktest]# vi next.txt 
httpd       ok
web01[192.168.1.101]
httpd       ok
tomcat      ok
sendmail    ok
web02[192.168.1.102]
httpd       ok
postfix     ok
web03[192.168.1.103]
httpd       ok
mysqld      ok
[root@os awktest]# awk '/^web/{T=$0;next}{print T":\t"$0;}' next.txt 
web01[192.168.1.101]:   httpd       ok
web01[192.168.1.101]:   tomcat      ok
web01[192.168.1.101]:   sendmail    ok
web02[192.168.1.102]:   httpd       ok
web02[192.168.1.102]:   postfix     ok
web03[192.168.1.103]:   httpd       ok
web03[192.168.1.103]:   mysqld      ok

    2、讀取一條記錄
      awk getline:輸出重定向需要使用getline函數。getline從標準輸入、管道或者當前正在處理的文件之外的其它輸入文件獲得輸入。它負責從輸入獲得下一行內容,並給NF,NR,FNR等內置變量賦值。
      用法說明:
         當其左在右無重寫向符|或<時,getline作用於當前文件,讀入當前文件的第一行給其後綴的變量var或$0,應該注意到,由於awk在處理getline之前已經讀入一行,所以getline得到的返回結果是隔行的
         當其左在右有重寫向符|或<時,geline則作用於定向輸入文件,由於該文件是剛打開,並沒有被awk讀入一行,只是getline讀入,那麼getline返回的是該文件的第一行,而不是隔行

[root@os awktest]# awk 'BEGIN{ "date" | getline out; print out }' test
Sat Mar 14 12:06:53 EDT 2020
[root@os awktest]# awk '{ getline } /root/ ' /etc/passwd 
operator:x:11:0:operator:/root:/sbin/nologin     #注意,這裏是隔行的,所以只匹配到一個

六、流程控制語句
    在linux awk的while、do-while和for語句中允許使用break,continue語句來控制流程走向,也允許exit語句退出。awk中,流程控制語句,語法結構,與C語言類似。有了這些,很多shell程序都可以交給awk,而且性能非常快
    

 #if語句
[root@os awktest]# awk ' BEGIN{test=100;if(test>90){print "very good"}else if(test>60){print "good"}else{prit "no pass"}}'            
very good

#while語句
[root@os awktest]# awk 'BEGIN{test=13;total=0;while(i<=test){total+=i;i++}print total}'
91   

#for語句(2種格式)                  
[root@os awktest]# awk 'BEGIN{for(k in ENVIRON){print k"="ENVIRON[k];}}'
AWKPATH=.:/usr/share/awk
OLDPWD=/root
SELINUX_LEVEL_REQUESTED=
SELINUX_ROLE_REQUESTED=
......
36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
[root@os awktest]# awk 'BEGIN{for(i=0;i<=13;i++){total+=i}print total;}'
91

七、數組應用
    1、數組的定義
        數字幫數組索引(下標):
         array[1]="sun"
         array[2]="shitou"
        字符串做數組索引(下標):
          array["first"]="www"
          array["last"]="name"
          array["birth"]="1990"

[root@os awktest]# awk 'BEGIN{array[1]="sun";array[2]="shitou";array["first"]="www";array["last"]="name";array["birth"]="1990"; { print array[1] "\n" array["first"]}}'
sun
www
[root@os awktest]# awk 'BEGIN{array[1]="sun";array[2]="shitou";array["first"]="www";array["last"]="name";array["birth"]="1990"; { for(item in array){print array[item]}}}'
1990
www
name
sun
shitou
[root@os awktest]# awk 'BEGIN{array[1]="sun";array[2]="shitou";array["first"]="www";array["last"]="name";array["birth"]="1990"; { for(i=1;i<=2;i++){print array[i]};} }'
sun
shitou

    2、數組相關函數

#輸出數組長度
[root@os awktest]# awk 'BEGIN{info="it is a test";lens=split(info,tA," ");print length(tA), lens;}'
4 4
#length返回字符串以及數組長度,split進行分割字符串爲數組,也會返回分割得到的數組長度



 

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