歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

AWK簡明教程

AWK簡明教程   我從netstat命令中提取了如下信息作為用例:   $ cat netstat.txt Proto Recv-Q Send-Q Local-Address          Foreign-Address             State tcp        0      0 0.0.0.0:3306           0.0.0.0:*                   LISTEN tcp        0      0 0.0.0.0:80             0.0.0.0:*                   LISTEN tcp        0      0 127.0.0.1:9000         0.0.0.0:*                   LISTEN tcp        0      0 coolshell.cn:80        124.205.5.146:18245         TIME_WAIT tcp        0      0 coolshell.cn:80        61.140.101.185:37538        FIN_WAIT2 tcp        0      0 coolshell.cn:80        110.194.134.189:1032        ESTABLISHED tcp        0      0 coolshell.cn:80        123.169.124.111:49809       ESTABLISHED tcp        0      0 coolshell.cn:80        116.234.127.77:11502        FIN_WAIT2 tcp        0      0 coolshell.cn:80        123.169.124.111:49829       ESTABLISHED tcp        0      0 coolshell.cn:80        183.60.215.36:36970         TIME_WAIT tcp        0   4166 coolshell.cn:80        61.148.242.38:30901         ESTABLISHED tcp        0      1 coolshell.cn:80        124.152.181.209:26825       FIN_WAIT1 tcp        0      0 coolshell.cn:80        110.194.134.189:4796        ESTABLISHED tcp        0      0 coolshell.cn:80        183.60.212.163:51082        TIME_WAIT tcp        0      1 coolshell.cn:80        208.115.113.92:50601        LAST_ACK tcp        0      0 coolshell.cn:80        123.169.124.111:49840       ESTABLISHED tcp        0      0 coolshell.cn:80        117.136.20.85:50025         FIN_WAIT2 tcp        0      0 :::22                  :::*                        LISTEN 下面是最簡單最常用的awk示例,其輸出第1列和第4例,   其中單引號中的被大括號括著的就是awk的語句,注意,其只能被單引號包含。 其中的$1..$n表示第幾例。注:$0表示整個行。   $ awk '{print $1, $4}' netstat.txt Proto Local-Address tcp 0.0.0.0:3306 tcp 0.0.0.0:80 tcp 127.0.0.1:9000 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp coolshell.cn:80 tcp :::22 我們再來看看awk的格式化輸出,和C語言的printf沒什麼兩樣:   $ awk '{printf "%-8s %-8s %-8s %-18s %-22s %-15s\n",$1,$2,$3,$4,$5,$6}' netstat.txt Proto    Recv-Q   Send-Q   Local-Address      Foreign-Address        State tcp      0        0        0.0.0.0:3306       0.0.0.0:*              LISTEN tcp      0        0        0.0.0.0:80         0.0.0.0:*              LISTEN tcp      0        0        127.0.0.1:9000     0.0.0.0:*              LISTEN tcp      0        0        coolshell.cn:80    124.205.5.146:18245    TIME_WAIT tcp      0        0        coolshell.cn:80    61.140.101.185:37538   FIN_WAIT2 tcp      0        0        coolshell.cn:80    110.194.134.189:1032   ESTABLISHED tcp      0        0        coolshell.cn:80    123.169.124.111:49809  ESTABLISHED tcp      0        0        coolshell.cn:80    116.234.127.77:11502   FIN_WAIT2 tcp      0        0        coolshell.cn:80    123.169.124.111:49829  ESTABLISHED tcp      0        0        coolshell.cn:80    183.60.215.36:36970    TIME_WAIT tcp      0        4166     coolshell.cn:80    61.148.242.38:30901    ESTABLISHED tcp      0        1        coolshell.cn:80    124.152.181.209:26825  FIN_WAIT1 tcp      0        0        coolshell.cn:80    110.194.134.189:4796   ESTABLISHED tcp      0        0        coolshell.cn:80    183.60.212.163:51082   TIME_WAIT tcp      0        1        coolshell.cn:80    208.115.113.92:50601   LAST_ACK tcp      0        0        coolshell.cn:80    123.169.124.111:49840  ESTABLISHED tcp      0        0        coolshell.cn:80    117.136.20.85:50025    FIN_WAIT2 tcp      0        0        :::22              :::*                   LISTEN 脫掉外套   過濾記錄 我們再來看看如何過濾記錄(下面過濾條件為:第三列的值為0 && 第6列的值為LISTEN)   $ awk '$3==0 && $6=="LISTEN" ' netstat.txt tcp        0      0 0.0.0.0:3306               0.0.0.0:*              LISTEN tcp        0      0 0.0.0.0:80                 0.0.0.0:*              LISTEN tcp        0      0 127.0.0.1:9000             0.0.0.0:*              LISTEN tcp        0      0 :::22                      :::*                   LISTEN 其中的“==”為比較運算符。其他比較運算符:!=, >, <, >=, <=   我們來看看各種過濾記錄的方式:   $ awk ' $3>0 {print $0}' netstat.txt Proto Recv-Q Send-Q Local-Address          Foreign-Address             State tcp        0   4166 coolshell.cn:80        61.148.242.38:30901         ESTABLISHED tcp        0      1 coolshell.cn:80        124.152.181.209:26825       FIN_WAIT1 tcp        0      1 coolshell.cn:80        208.115.113.92:50601        LAST_ACK 如果我們需要表頭的話,我們可以引入內建變量NR:   $ awk '$3==0 && $6=="LISTEN" || NR==1 ' netstat.txt Proto Recv-Q Send-Q Local-Address          Foreign-Address             State tcp        0      0 0.0.0.0:3306           0.0.0.0:*                   LISTEN tcp        0      0 0.0.0.0:80             0.0.0.0:*                   LISTEN tcp        0      0 127.0.0.1:9000         0.0.0.0:*                   LISTEN tcp        0      0 :::22                  :::*                        LISTEN 再加上格式化輸出:   $ awk '$3==0 && $6=="LISTEN" || NR==1 {printf "%-20s %-20s %s\n",$4,$5,$6}' netstat.txt Local-Address        Foreign-Address      State 0.0.0.0:3306         0.0.0.0:*            LISTEN 0.0.0.0:80           0.0.0.0:*            LISTEN 127.0.0.1:9000       0.0.0.0:*            LISTEN :::22                :::*                 LISTEN 內建變量 說到了內建變量,我們可以來看看awk的一些內建變量:   $0 當前記錄(這個變量中存放著整個行的內容) $1~$n 當前記錄的第n個字段,字段間由FS分隔 FS 輸入字段分隔符 默認是空格或Tab NF 當前記錄中的字段個數,就是有多少列 NR 已經讀出的記錄數,就是行號,從1開始,如果有多個文件話,這個值也是不斷累加中。 FNR 當前記錄數,與NR不同的是,這個值會是各個文件自己的行號 RS 輸入的記錄分隔符, 默認為換行符 OFS 輸出字段分隔符, 默認也是空格 ORS 輸出的記錄分隔符,默認為換行符 FILENAME 當前輸入文件的名字 怎麼使用呢,比如:我們如果要輸出行號:   $ awk '$3==0 && $6=="ESTABLISHED" || NR==1 {printf "%02s %s %-20s %-20s %s\n",NR, FNR, $4,$5,$6}' netstat.txt 01 1 Local-Address        Foreign-Address      State 07 7 coolshell.cn:80      110.194.134.189:1032 ESTABLISHED 08 8 coolshell.cn:80      123.169.124.111:49809 ESTABLISHED 10 10 coolshell.cn:80      123.169.124.111:49829 ESTABLISHED 14 14 coolshell.cn:80      110.194.134.189:4796 ESTABLISHED 17 17 coolshell.cn:80      123.169.124.111:49840 ESTABLISHED 指定分隔符   $  awk  'BEGIN{FS=":"} {print $1,$3,$6}' /etc/passwd root 0 /root bin 1 /bin daemon 2 /sbin adm 3 /var/adm lp 4 /var/spool/lpd sync 5 /sbin shutdown 6 /sbin halt 7 /sbin 上面的命令也等價於:(-F的意思就是指定分隔符)   1 $ awk  -F: '{print $1,$3,$6}' /etc/passwd 注:如果你要指定多個分隔符,你可以這樣來:   1 awk -F '[;:]' 再來看一個以\t作為分隔符輸出的例子(下面使用了/etc/passwd文件,這個文件是以:分隔的):   $ awk  -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd root    0       /root bin     1       /bin daemon  2       /sbin adm     3       /var/adm lp      4       /var/spool/lpd sync    5       /sbin 脫掉襯衫   字符串匹配 我們再來看幾個字符串匹配的示例:   $ awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt 1       Local-Address   Foreign-Address State 6       coolshell.cn:80 61.140.101.185:37538    FIN_WAIT2 9       coolshell.cn:80 116.234.127.77:11502    FIN_WAIT2 13      coolshell.cn:80 124.152.181.209:26825   FIN_WAIT1 18      coolshell.cn:80 117.136.20.85:50025     FIN_WAIT2   $ $ awk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt 1       Local-Address   Foreign-Address State 5       coolshell.cn:80 124.205.5.146:18245     TIME_WAIT 6       coolshell.cn:80 61.140.101.185:37538    FIN_WAIT2 9       coolshell.cn:80 116.234.127.77:11502    FIN_WAIT2 11      coolshell.cn:80 183.60.215.36:36970     TIME_WAIT 13      coolshell.cn:80 124.152.181.209:26825   FIN_WAIT1 15      coolshell.cn:80 183.60.212.163:51082    TIME_WAIT 18      coolshell.cn:80 117.136.20.85:50025     FIN_WAIT2 上面的第一個示例匹配FIN狀態, 第二個示例匹配WAIT字樣的狀態。其實 ~ 表示模式開始。/ /中是模式。這就是一個正則表達式的匹配。   其實awk可以像grep一樣的去匹配第一行,就像這樣:   $ awk '/LISTEN/' netstat.txt tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN tcp        0      0 :::22                   :::*                    LISTEN 我們可以使用 “/FIN|TIME/” 來匹配 FIN 或者 TIME : 9 $ awk '$6 ~ /FIN|TIME/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt 1       Local-Address   Foreign-Address State 5       coolshell.cn:80 124.205.5.146:18245     TIME_WAIT 6       coolshell.cn:80 61.140.101.185:37538    FIN_WAIT2 9       coolshell.cn:80 116.234.127.77:11502    FIN_WAIT2 11      coolshell.cn:80 183.60.215.36:36970     TIME_WAIT 13      coolshell.cn:80 124.152.181.209:26825   FIN_WAIT1 15      coolshell.cn:80 183.60.212.163:51082    TIME_WAIT 18      coolshell.cn:80 117.136.20.85:50025     FIN_WAIT2 再來看看模式取反的例子:   $ awk '$6 !~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt 1       Local-Address   Foreign-Address State 2       0.0.0.0:3306    0.0.0.0:*       LISTEN 3       0.0.0.0:80      0.0.0.0:*       LISTEN 4       127.0.0.1:9000  0.0.0.0:*       LISTEN 7       coolshell.cn:80 110.194.134.189:1032    ESTABLISHED 8       coolshell.cn:80 123.169.124.111:49809   ESTABLISHED 10      coolshell.cn:80 123.169.124.111:49829   ESTABLISHED 12      coolshell.cn:80 61.148.242.38:30901     ESTABLISHED 14      coolshell.cn:80 110.194.134.189:4796    ESTABLISHED 16      coolshell.cn:80 208.115.113.92:50601    LAST_ACK 17      coolshell.cn:80 123.169.124.111:49840   ESTABLISHED 19      :::22   :::*    LISTEN 或是:   1 awk '!/WAIT/' netstat.txt 折分文件   awk拆分文件很簡單,使用重定向就好了。下面這個例子,是按第6例分隔文件,相當的簡單(其中的NR!=1表示不處理表頭)。   $ awk 'NR!=1{print > $6}' netstat.txt   $ ls ESTABLISHED  FIN_WAIT1  FIN_WAIT2  LAST_ACK  LISTEN  netstat.txt  TIME_WAIT   $ cat ESTABLISHED tcp        0      0 coolshell.cn:80        110.194.134.189:1032        ESTABLISHED tcp        0      0 coolshell.cn:80        123.169.124.111:49809       ESTABLISHED tcp        0      0 coolshell.cn:80        123.169.124.111:49829       ESTABLISHED tcp        0   4166 coolshell.cn:80        61.148.242.38:30901         ESTABLISHED tcp        0      0 coolshell.cn:80        110.194.134.189:4796        ESTABLISHED tcp        0      0 coolshell.cn:80        123.169.124.111:49840       ESTABLISHED   $ cat FIN_WAIT1 tcp        0      1 coolshell.cn:80        124.152.181.209:26825       FIN_WAIT1   $ cat FIN_WAIT2 tcp        0      0 coolshell.cn:80        61.140.101.185:37538        FIN_WAIT2 tcp        0      0 coolshell.cn:80        116.234.127.77:11502        FIN_WAIT2 tcp        0      0 coolshell.cn:80        117.136.20.85:50025         FIN_WAIT2   $ cat LAST_ACK tcp        0      1 coolshell.cn:80        208.115.113.92:50601        LAST_ACK   $ cat LISTEN tcp        0      0 0.0.0.0:3306           0.0.0.0:*                   LISTEN tcp        0      0 0.0.0.0:80             0.0.0.0:*                   LISTEN tcp        0      0 127.0.0.1:9000         0.0.0.0:*                   LISTEN tcp        0      0 :::22                  :::*                        LISTEN   $ cat TIME_WAIT tcp        0      0 coolshell.cn:80        124.205.5.146:18245         TIME_WAIT tcp        0      0 coolshell.cn:80        183.60.215.36:36970         TIME_WAIT tcp        0      0 coolshell.cn:80        183.60.212.163:51082        TIME_WAIT 你也可以把指定的列輸出到文件:   1 awk 'NR!=1{print $4,$5 > $6}' netstat.txt 再復雜一點:(注意其中的if-else-if語句,可見awk其實是個腳本解釋器)   $ awk 'NR!=1{if($6 ~ /TIME|ESTABLISHED/) print > "1.txt"; else if($6 ~ /LISTEN/) print > "2.txt"; else print > "3.txt" }' netstat.txt   $ ls ?.txt 1.txt  2.txt  3.txt   $ cat 1.txt tcp        0      0 coolshell.cn:80        124.205.5.146:18245         TIME_WAIT tcp        0      0 coolshell.cn:80        110.194.134.189:1032        ESTABLISHED tcp        0      0 coolshell.cn:80        123.169.124.111:49809       ESTABLISHED tcp        0      0 coolshell.cn:80        123.169.124.111:49829       ESTABLISHED tcp        0      0 coolshell.cn:80        183.60.215.36:36970         TIME_WAIT tcp        0   4166 coolshell.cn:80        61.148.242.38:30901         ESTABLISHED tcp        0      0 coolshell.cn:80        110.194.134.189:4796        ESTABLISHED tcp        0      0 coolshell.cn:80        183.60.212.163:51082        TIME_WAIT tcp        0      0 coolshell.cn:80        123.169.124.111:49840       ESTABLISHED   $ cat 2.txt tcp        0      0 0.0.0.0:3306           0.0.0.0:*                   LISTEN tcp        0      0 0.0.0.0:80             0.0.0.0:*                   LISTEN tcp        0      0 127.0.0.1:9000         0.0.0.0:*                   LISTEN tcp        0      0 :::22                  :::*                        LISTEN   $ cat 3.txt tcp        0      0 coolshell.cn:80        61.140.101.185:37538        FIN_WAIT2 tcp        0      0 coolshell.cn:80        116.234.127.77:11502        FIN_WAIT2 tcp        0      1 coolshell.cn:80        124.152.181.209:26825       FIN_WAIT1 tcp        0      1 coolshell.cn:80        208.115.113.92:50601        LAST_ACK tcp        0      0 coolshell.cn:80        117.136.20.85:50025         FIN_WAIT2 統計 下面的命令計算所有的C文件,CPP文件和H文件的文件大小總和。   1 2 $ ls -l  *.cpp *.c *.h | awk '{sum+=$5} END {print sum}' 2511401 我們再來看一個統計各個connection狀態的用法:(我們可以看到一些編程的影子了,大家都是程序員我就不解釋了。注意其中的數組的用法)   $ awk 'NR!=1{a[$6]++;} END {for (i in a) print i ", " a[i];}' netstat.txt TIME_WAIT, 3 FIN_WAIT1, 1 ESTABLISHED, 6 FIN_WAIT2, 3 LAST_ACK, 1 LISTEN, 4 再來看看統計每個用戶的進程的占了多少內存(注:sum的RSS那一列)   $ ps aux | awk 'NR!=1{a[$1]+=$6;} END { for(i in a) print i ", " a[i]"KB";}' dbus, 540KB mysql, 99928KB www, 3264924KB root, 63644KB hchen, 6020KB 脫掉內衣   awk腳本 在上面我們可以看到一個END關鍵字。END的意思是“處理完所有的行的標識”,即然說到了END就有必要介紹一下BEGIN,這兩個關鍵字意味著執行前和執行後的意思,語法如下:   BEGIN{ 這裡面放的是執行前的語句 } END {這裡面放的是處理完所有的行後要執行的語句 } {這裡面放的是處理每一行時要執行的語句} 為了說清楚這個事,我們來看看下面的示例:   假設有這麼一個文件(學生成績表):   $ cat score.txt Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62 我們的awk腳本如下(我沒有寫有命令行上是因為命令行上不易讀,另外也在介紹另一種用法):   $ cat cal.awk #!/bin/awk -f #運行前 BEGIN {     math = 0     english = 0     computer = 0       printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"     printf "---------------------------------------------\n" } #運行中 {     math+=$3     english+=$4     computer+=$5     printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5 } #運行後 END {     printf "---------------------------------------------\n"     printf "  TOTAL:%10d %8d %8d \n", math, english, computer     printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR } 我們來看一下執行結果:(也可以這樣運行 ./cal.awk score.txt)   $ awk -f cal.awk score.txt NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL --------------------------------------------- Marry  2143     78       84       77      239 Jack   2321     66       78       45      189 Tom    2122     48       77       71      196 Mike   2537     87       97       95      279 Bob    2415     40       57       62      159 ---------------------------------------------   TOTAL:       319      393      350 AVERAGE:     63.80    78.60    70.00 環境變量 即然說到了腳本,我們來看看怎麼和環境變量交互:(使用-v參數和ENVIRON,使用ENVIRON的環境變量需要export)   $ x=5   $ y=10 $ export y   $ echo $x $y 5 10   $ awk -v val=$x '{print $1, $2, $3, $4+val, $5+ENVIRON["y"]}' OFS="\t" score.txt Marry   2143    78      89      87 Jack    2321    66      83      55 Tom     2122    48      82      81 Mike    2537    87      102     105 Bob     2415    40      62      72 幾個花活   最後,我們再來看幾個小例子:   #從file文件中找出長度大於80的行 awk 'length>80' file   #按連接數查看客戶端IP netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr   #打印99乘法表 seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'
Copyright © Linux教程網 All Rights Reserved