Shell正則四劍客 | awk命令(資料)

簡介

        awk是一個強大的文本分析工具,相對於grep的查找,sed的編輯,awk在其對數據分析並生成報告時,顯得尤其強大。簡單來講awk就是把文件逐行的讀入,以空格爲默認分隔符將每行切片,切開的部分再進行各類分析處理。php

      awk有3個不一樣版本: awk、nawk和gawk,未做特別說明,通常指gawk,gawk 是 AWK 的 GNU 版本。mysql

       AWK是一個優良的文本處理工具,Linux及Unix環境中現有的功能最強大的數據處理引擎之一,以Aho、Weinberger、Kernighan三位發明者名字首字母命名爲AWK,AWK是一個行級文本高效處理工具,AWK通過改進生成的新的版本有Nawk、Gawk,通常Linux默認爲Gawk,Gawk是 AWK的GNU開源免費版本。linux

       AWK基本原理是逐行處理文件中的數據,查找與命令行中所給定內容相匹配的模式,若是發現匹配內容,則進行下一個編程步驟,若是找不到匹配內容,則 繼續處理下一行。程序員

使用方法

awk '{pattern + action}' {filenames}正則表達式

       儘管操做可能會很複雜,但語法老是這樣,其中 pattern 表示 AWK 在數據中查找的內容,而 action 是在找到匹配內容時所執行的一系列命令。花括號({})不須要在程序中始終出現,但它們用於根據特定的模式對一系列指令進行分組。 pattern就是要表示的正則表達式,用斜槓括起來。sql

 

         awk語言的最基本功能是在文件或者字符串中基於指定規則瀏覽和抽取信息,awk抽取信息後,才能進行其餘文本操做。完整的awk腳本一般用來格式化文本文件中的信息。shell

         一般,awk是以文件的一行爲處理單位的。awk每接收文件的一行,而後執行相應的命令,來處理文本。express

一、AWK基本語法參數詳解:apache

  • 單引號’ ‘是爲了和shell命令區分開;編程

  • 大括號{ }表示一個命令分組;

  • pattern是一個過濾器,表示匹配pattern條件的行才進行Action處理;

  • action是處理動做,常見動做爲Print;

  • 使用#做爲註釋,pattern和action能夠只有其一,但不能二者都沒有。

 

二、AWK內置變量詳解:

$0 當前記錄(這個變量中存放着整個行的內容)
$1~$n 當前記錄的第n個字段,字段間由FS分隔
FS 輸入字段分隔符 默認是空格或Tab
NF 當前記錄中的字段個數,就是有多少列
NR 已經讀出的記錄數,就是行號,從1開始,若是有多個文件話,這個值也是不斷累加中。
FNR 當前記錄數,與NR不一樣的是,這個值會是各個文件本身的行號
RS 輸入的記錄分隔符, 默認爲換行符
OFS 輸出字段分隔符, 默認也是空格
ORS 輸出的記錄分隔符,默認爲換行符
FILENAME 當前輸入文件的名字

 

調用awk

 

有三種方式調用awk

1.命令行方式

awk [-F  field-separator]  'commands'  input-file(s)

其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的文件。

在awk中,文件的每一行中,由域分隔符分開的每一項稱爲一個域。一般,在不指名-F域分隔符的狀況下,默認的域分隔符是空格。

 

2.shell腳本方式

將全部的awk命令插入一個文件,並使awk程序可執行,而後awk命令解釋器做爲腳本的首行,一遍經過鍵入腳本名稱來調用。

至關於shell腳本首行的:#!/bin/sh

能夠換成:#!/bin/awk

3.將全部的awk命令插入一個單獨文件,而後調用:

awk -f awk-script-file input-file(s)

其中,-f選項加載awk-script-file中的awk腳本,input-file(s)跟上面的是同樣的。

awk實例 : 

過濾記錄

過濾條件爲:第三列的值爲0 && 第6列的值爲LISTEN)

1

2

3

4

5

$ 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                      :::*                   LISTE

須要表頭的話,咱們能夠引入內建變量NR:

1

2

3

4

5

6

$ 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                  :::*                        LIST

再加上格式化輸出:

1

2

3

4

5

6

$ 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

若是要輸出行號:

1

2

3

4

5

6

7

$ 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的意思就是指定分隔符)

$ awk  -F: '{print $1,$3,$6}' /etc/passwd

要指定多個分隔符,你能夠這樣來:

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 :

$ 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

或是:

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

能夠把指定的列輸出到文件:

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
 
$ 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

統計

下面的命令計算全部的C文件,CPP文件和H文件的文件大小總和。

$ 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

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")}'

 

awk工做流程

$0          則表示全部域

$1          表示第一個域;

$n          表示第n個域;

默認域分隔符是」空白鍵」 或 「鍵」,

因此$1表示登陸用戶,$3表示登陸用戶ip

 

awk內置變量

 

AWK命令

awk 具備 grep 和 sed命令的特性,同時 AWK針對列進行匹配

語法格式

Usage: awk [options] -f progfile [--] file ...
Usage: awk [options] [--] 'program' file ...

經常使用選項

  • -F fs fs指定輸入分隔符,fs能夠是字符串或正則表達式;如-F ":"

  • -vvar=value 賦值一個用戶定義變量,將外部變量傳遞給awk

  • -f progfile 從腳本文件中讀取awk命令

  • -m[fr]val 對val值設置內在限制;

  • -mf選項限制分配給val的最大塊數目;

  • -mr選項限制記錄最大數目;

  • 此選項爲awk的擴展功能,在標準awk中不適用;

 

入門實例

假設last -n 5的輸出以下

# last -n 5 僅取出前五行

root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in

root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)

root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)

dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)

root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)

若是隻是顯示最近登陸的5個賬號

#last -n 5 | awk  '{print $1}'

root

root

root

dmtsai

root

awk工做流程是這樣的:讀入有’n’換行符分割的一條記錄,而後將記錄按指定的域分隔符劃分域,填充域,$0則表示全部域,$1表示第一個域,$n表示第n個域。默認域分隔符是」空白鍵」 或 「鍵」,因此$1表示登陸用戶,$3表示登陸用戶ip,以此類推。

 

若是隻是顯示/etc/passwd的帳戶

#cat /etc/passwd |awk  -F ':'  '{print $1}'  

root

daemon

bin

sys

這種是awk+action的示例,每行都會執行action{print $1}。

-F指定域分隔符爲’:’。

若是隻是顯示/etc/passwd的帳戶和帳戶對應的shell,而帳戶與shell之間以tab鍵分割

#cat /etc/passwd |awk  -F ':'  '{print $1"t"$7}'

root    /bin/bash

daemon  /bin/sh

bin     /bin/sh

sys     /bin/sh

若是隻是顯示/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操做。

 

搜索/etc/passwd有root關鍵字的全部行

#awk -F: '/root/' /etc/passwd

root:x:0:0:root:/root:/bin/bash

這種是pattern的使用示例,匹配了pattern(這裏是root)的行纔會執行action(沒有指定action,默認輸出每行的內容)。

 

搜索支持正則,例如找root開頭的: awk -F: ‘/^root/’ /etc/passwd

 

搜索/etc/passwd有root關鍵字的全部行,並顯示對應的shell

# awk -F: '/root/{print $7}' /etc/passwd            

/bin/bash

這裏指定了action{print $7}

 

awk內置變量

 

awk有許多內置變量用來設置環境信息,這些變量能夠被改變,下面給出了最經常使用的一些變量。

ARGC               命令行參數個數

ARGV               命令行參數排列

ENVIRON            支持隊列中系統環境變量的使用

FILENAME           awk瀏覽的文件名

FNR                瀏覽文件的記錄數

FS                 設置輸入域分隔符,等價於命令行 -F選項

NF                 瀏覽記錄的域的個數

NR                 已讀的記錄數

OFS                輸出域分隔符

ORS                輸出記錄分隔符

RS                 控制記錄分隔符

 

此外,$0變量是指整條記錄。$1表示當前行的第一個域,$2表示當前行的第二個域,……以此類推

 

統計/etc/passwd:文件名,每行的行號,每行的列數,對應的完整行內容:

#awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd

filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash

filename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh

filename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh

filename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh

 

使用printf替代print,可讓代碼更加簡潔,易讀

awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%sn",FILENAME,NR,NF,$0)}'/etc/passwd

print和printf

 

       awk中同時提供了print和printf兩種打印輸出的函數。

      其中print函數的參數能夠是變量、數值或者字符串。字符串必須用雙引號引用,參數用逗號分隔。若是沒有逗號,參數就串聯在一塊兒而沒法區分。這裏,逗號的做用與輸出文件的分隔符的做用是同樣的,只是後者是空格而已。

      printf函數,其用法和c語言中printf基本類似,能夠格式化字符串,輸出複雜時,printf更加好用,代碼更易懂。

 

awk編程

變量和賦值

除了awk的內置變量,awk還能夠自定義變量。

 

下面統計/etc/passwd的帳戶人數

awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd

root:x:0:0:root:/root:/bin/bash

......

user count is 40

count是自定義變量。以前的action{}裏都是隻有一個print,其實print只是一個語句,而action{}能夠有多個語句,以;號隔開。

 

這裏沒有初始化count,雖然默認是0,可是穩當的作法仍是初始化爲0:

awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd

[start]user count is  0

root:x:0:0:root:/root:/bin/bash

...

[end]user count is  40

 

統計某個文件夾下的文件佔用的字節數

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'

[end]size is 8657198

 

若是以M爲單位顯示:

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}'

[end]size is 8.25889 M

 

注意,統計不包括文件夾的子目錄。

 

條件語句

awk中的條件語句是從C語言中借鑑來的,見以下聲明方式:

if (expression) {

    statement;

    statement;

    ... ...

}

 

if (expression) {

    statement;

} else {

    statement2;

}

 

if (expression) {

    statement1;

} else if (expression1) {

    statement2;

} else {

    statement3;

}

 

統計某個文件夾下的文件佔用的字節數,過濾4096大小的文件(通常都是文件夾):

ls -l | awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'

[end]size is 8.22339 M

循環語句

awk中的循環語句一樣借鑑於C語言,支持while、do/while、for、break、continue,這些關鍵字的語義和C語言中的語義徹底相同。

數組

由於awk中數組的下標能夠是數字和字母,數組的下標一般被稱爲關鍵字(key)。值和關鍵字都存儲在內部的一張針對key/value應用hash的表格裏。因爲hash不是順序存儲,所以在顯示數組內容時會發現,它們並非按照你預料的順序顯示出來的。數組和變量同樣,都是在使用時自動建立的,awk也一樣會自動判斷其存儲的是數字仍是字符串。通常而言,awk中的數組用來從記錄中收集信息,能夠用於計算總和、統計單詞以及跟蹤模板被匹配的次數等等。

 

顯示/etc/passwd的帳戶

awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i ' /etc/passwd

0 root

1 daemon

2 bin

3 sys

4 sync

5 games

......

這裏使用for循環遍歷數組

 

awk使用案例



## $1 $2...$n 表示字段;$0 表示全部字段
head -n2 test.txt | awk -F ":" '{print $0}'
head -n2 test.txt | awk -F ":" '{print $1}'## 輸入字段分隔符
head -n2 test.txt | awk -F ":" '{print $1"#"$2"#"$3}'
head -n2 test.txt | awk -F ":" '{OFS="#"}{print $1,$2,$3}'## 字符串過濾【具備grep過濾功能】
awk -F ":" '/root/' test.txt ## 匹配字符串爲root的行
awk -F ":" '$1 ~/root/' test.txt ## 匹配第一字段包含root的行

## awk的數學運算
awk -F ":" '$3>$4' /etc/passwd
awk -F ":" '$3>800 ||  $7=="/bin/bash"' /etc/passwd
awk -F ":" '$7!="/sbin/nologin"' /etc/passwd

## if判斷用例
awk -F ":" '{if($1=="root"){print $0} }' text
awk -F ":" '{if($3>=20){print $3}}' text## awk的循環
awk -F ":" '{(tot=tot+$3)}; END {print tot}' text

awk小練習

打印行號【awk/grep實現】

## awk寫法
[root@shell awk]# awk -F ":" '/root/{print NR":"$0}' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
## grep寫法
[root@shell awk]# grep -n 'root' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin

匹配包含 root 的行【awk/grep實現】

  • ## awk寫法

  • [root@shell awk]# awk -F ":" '/root/' /etc/passwd

  • root:x:0:0:root:/root:/bin/bash

  • operator:x:11:0:operator:/root:/sbin/nologin

  • ## grep寫法

  • [root@shell awk]# grep 'root' /etc/passwd

  • root:x:0:0:root:/root:/bin/bash

  • operator:x:11:0:operator:/root:/sbin/nologin

匹配第一字段爲 root的行

  1. [root@shell awk]# awk -F ":" '$1 ~/root/' /etc/passwd

  2. root:x:0:0:root:/root:/bin/bash

  3. rootaaaaa:x:0:0:root:/root:/bin/bash

  4. irootaaaaa:x:0:0:root:/root:/bin/bash

匹配包含root 或 bash 的行【awk/grep實現】

  1. ## awk寫法(一)

  2. [root@shell awk]# awk -F ":" '/root|bash/ {print $0}' /etc/passwd

  3. root:x:0:0:root:/root:/bin/bash

  4. operator:x:11:0:operator:/root:/sbin/nologin

  5. ## awk寫法(二)

  6. [root@shell awk]# awk -F ":" '/root/ || /bash/ {print $0}' /etc/passwd

  7. root:x:0:0:root:/root:/bin/bash

  8. operator:x:11:0:operator:/root:/sbin/nologin

  9.  

  10. ## grep寫法

  11. [root@shell awk]# grep -E "root|bash" /etc/passwd

  12. root:x:0:0:root:/root:/bin/bash

  13. operator:x:11:0:operator:/root:/sbin/nologin

匹配數學運算



## 匹配 $3等於字符串0
[root@shell awk]# awk -F ":" '$3=="0"' /etc/passwd
root:x:0:0:root:/root:/bin/bash## 匹配 $3 大於等於字符串 10
[root@ansible-master awk]# head -n 5 text |awk -F ":" '$3>="10"'
rootaaaaa:x:10:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin## 匹配 $3 大於等於數字 10
[root@ansible-master awk]# head -n 5 text |awk -F ":" '$3>=10'
rootaaaaa:x:10:0:root:/root:/bin/bash## 匹配$7字段 不等於字符串·/bin/nologin·
[root@ansible-master awk]# head -n 5 text |awk -F ":" '$7!="/bin/nologin"'​​​​​
root:x:0:0:root:/root:/bin/bash
rootaaaaa:x:10:0:root:/root:/bin/bash
irootaaaaa:x:01:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

 

匹配字段添加分隔符

## 方法1
[root@shell awk]# awk -F ":" '{OFS="#"} /root|bash/ {print $1,$2,$5}' /etc/passwd
root#x#root
operator#x#operator## 方法2
[root@shell awk]# awk -F ":" '/root|bash/ {print $1"#"$2"#"$5}' /etc/passwd
root#x#root
operator#x#operator

 

匹配條件字段

[root@shell awk]# awk -F ":" '{OFS="#"}{if($3>800){print $1,$3,$7}}' /etc/passwd
polkitd#999#/sbin/nologin
chrony#998#/sbin/nologin
jenkins#997#/bin/false
saslauth#996#/sbin/nologin

NR和$NR區別

  • NR 表示,只打印行號

  • $NR 表示,根據當前行號打印相應字段(好比:第1行,打印 $1字段;第2行,打印$2字段)

## NR 表示,只打印行號
[root@ansible-master awk]# head -6 text | awk -F ":" '{print NR, $0}'
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync## 匹配NR 大於 20 的行
[root@ansible-master awk]# awk -F ":" 'NR>20 {print NR,$0}' text
21 chrony:x:998:996::/var/lib/chrony:/sbin/nologin
22 jenkins:x:997:993:Jenkins Automation Server:/var/lib/jenkins:/bin/false
23 saslauth:x:996:76:Saslauthd user:/run/saslauthd:/sbin/nologin
24 mailnull:x:47:47::/var/spool/mqueue:/sbin/nologin
25 smmsp:x:51:51::/var/spool/mqueue:/sbin/nologin## 

$NR 表示,根據當前行號打印相應的字段
[root@ansible-master awk]# head -6 text | awk -F ":" '{print $NR, $0}'
root root:x:0:0:root:/root:/bin/bashx bin:x:1:1:bin:/bin:/sbin/nologin
2 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
lp lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
/sbin sync:x:5:0:sync:/sbin:/bin/sync

 

awk的條件判斷使用

 192
 81
 999## 判斷,若是$1字段 等於 字符串root 則打印
[root@ansible-master awk]# awk -F ":" '{if($1=="root"){print $0} }' text
root:x:0:0:root:/root:/bin/bash## 判斷,若是$3字段 大於 數字20 則打印
[root@ansible-master awk]# awk -F ":" '{if($3>=20){print $3}}' text
99

awk的循環

 4707## 求和 文件全部第3列
[root@ansible-master awk]# awk -F ":" '{(tot=tot+$3)}; END {print tot}' text

 

常見問題 :

一、下面統計/etc/passwd的帳戶人數

#awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd

 

二、統計/etc/passwd:文件名,每行的行號,每行的列數,對應的完整行內容:

#awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd

 

三、搜索/etc/passwd有root關鍵字的全部行,並顯示對應的shell

# awk -F: '/root/{print $7}' /etc/passwd   

 

四、只是顯示最近登陸的5個賬號

#last -n 5 | awk  '{print $1}'

 

五、顯示/etc/passwd的帳戶

#cat /etc/passwd |awk  -F ':'  '{print $1}'  

 

六、只是顯示/etc/passwd的帳戶和帳戶對應的shell,而帳戶與shell之間以tab鍵分割

#cat /etc/passwd |awk  -F ':'  '{print $1"t"$7}'

 

七、只是顯示/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"}'

 

八、搜索/etc/passwd有root關鍵字的全部行

#awk -F: '/root/' /etc/passwd

 

九、使用printf替代print,可讓代碼更加簡潔,易讀

awk  -F ':'  '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%sn",FILENAME,NR,NF,$0)}'/etc/passwd

十、下面統計/etc/passwd的帳戶人數

awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd

root:x:0:0:root:/root:/bin/bash

......

user count is 40

 

十一、沒有初始化count,默認是0,把他們都初始化爲0:

awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /etc/passwd

[start]user count is  0

root:x:0:0:root:/root:/bin/bash

...

[end]user count is  40

 

十二、統計某個文件夾下的文件佔用的字節數

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'

[end]size is 8657198

 

1三、若是以M爲單位顯示:

ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size/1024/1024,"M"}'

[end]size is 8.25889 M

注意,統計不包括文件夾的子目錄。

 

1四、統計某個文件夾下的文件佔用的字節數,過濾4096大小的文件(通常都是文件夾):

ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'

[end]size is 8.22339 M

 

1五、顯示/etc/passwd的帳戶

#awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i ' /etc/passwd

0 root

1 daemon

2 bin

3 sys

4 sync

5 games

 

1六、AWK打印硬盤設備名稱,默認以空格爲分割:

df -h | awk ‘{print $1}’

 

1七、AWK以空格、冒號、\t、分號爲分割:

awk -F ‘[ :\t;]’ ‘{print $1}’ jfedu.txt

 

1八、AWK以冒號分割,打印第一列,同時將內容追加到/tmp/awk.log下:

awk -F ‘[ :\t;]’ ‘{print $1}’ jfedu.txt

 

1九、打印jfedu.txt文件中的第3行至第5行,NR表示打印行,$0表示文本全部域:

awk ‘NR==3,NR==5 {print}’ jfedu.txt

awk ‘NR==3,NR==5 {print $0}’ jfedu.txt

 

20、打印jfedu.txt文件中,長度大於80的行號:

awk ‘length($0)>80 {print NR}’ jfedu.txt

 

2一、AWK引用Shell變量,使用-v或者雙引號+單引號便可:

awk -v STR=hello ‘{print STR,$NF}’ jfedu.txt

STR=」hello」;echo| awk ‘{print 「‘${STR}'」;}’

 

2二、Awk統計服務器狀態鏈接數:

netstat -an | awk ‘/tcp/ {s[$NF]++} END {for(a in s) {print a,s[a]}}’

netstat -an | awk ‘/tcp/ {print $NF}’ | sort | uniq -c

 

2三、查看每個IP訪問了多少個頁面:

awk '{++S[$1]} END {for (a in S) print a,S[a]}' log_file > log.txt sort -n -t ' ' -k 2 log.txt 配合sort進一步排序

 

2四、將每一個IP訪問的頁面數進行從小到大排序:

awk '{++S[$1]} END {for (a in S) print S[a],a}' log_file | sort -n

 

2五、去掉搜索引擎統計的頁面:

awk '{print $12,$1}' log_file | grep ^"Mozilla | awk '{print $2}' |sort | uniq | wc -l

 

2六、查看2015年8月16日14時這一個小時內有多少IP訪問:

awk '{print $4,$1}' log_file | grep 16/Aug/2015:14 | awk '{print $2}'| sort | uniq | wc -l

 

2七、查看訪問前十個ip地址

awk '{print $1}' |sort|uniq -c|sort -nr |head -10 access_log

 

2八、niq -c 至關於分組統計並把統計數放在最前面

cat access.log|awk '{print $1}'|sort|uniq -c|sort -nr|head -10

cat access.log|awk '{counts[$(11)]+=1}; END {for(url in counts) print counts[url], url}

 

2九、訪問次數最多的10個文件或頁面

cat log_file|awk '{print $11}'|sort|uniq -c|sort -nr | head -10 cat log_file|awk '{print $11}'|sort|uniq -c|sort -nr|head -20 awk '{print $1}' log_file |sort -n -r |uniq -c | sort -n -r | head -20

30、訪問量最大的前20個ip

經過子域名訪問次數,依據referer來計算,稍有不許

cat access.log | awk '{print $11}' | sed -e ' s/http:////' -e ' s//.*//' | sort | uniq -c | sort -rn | head -20

 

3一、列出傳輸大小最大的幾個文件

cat www.access.log |awk '($7~/.php/){print $10 " " $1 " " $4 " " $7}'|sort -nr|head -100

3二、列出輸出大於200000byte(約200kb)的頁面以及對應頁面發生次數

cat www.access.log |awk '($10 > 200000 && $7~/.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100

 

3三、若是日誌最後一列記錄的是頁面文件傳輸時間,則有列出到客戶端最耗時的頁面

cat www.access.log |awk '($7~/.php/){print $NF " " $1 " " $4 " " $7}'|sort -nr|head -100

3四、列出最最耗時的頁面(超過60秒的)的以及對應頁面發生次數

cat www.access.log |awk '($NF > 60 && $7~/.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100

 

3五、列出傳輸時間超過 30 秒的文件

cat www.access.log |awk '($NF > 30){print $7}'|sort -n|uniq -c|sort -nr|head -20

 

3六、列出當前服務器每一進程運行的數量,倒序排列

ps -ef | awk -F ' ' '{print $8 " " $9}' |sort | uniq -c |sort -nr |head -20

3七、分析日誌文件下 2012-05-04 訪問頁面最高 的前20個 URL 並排序

cat access.log |grep '04/May/2012'| awk '{print $11}'|sort|uniq -c|sort -nr|head -20

 

3八、查詢受訪問頁面的URL地址中 含有 www.abc.com 網址的 IP 地址

cat access_log | awk '($11~/www.abc.com/){print $1}'|sort|uniq -c|sort -nr

3九、獲取訪問最高的10個IP地址 同時也能夠按時間來查詢

cat linewow-access.log|awk '{print $1}'|sort|uniq -c|sort -nr|head -10

40、時間段查詢日誌時間段的狀況

cat log_file | egrep '15/Aug/2015|16/Aug/2015' |awk '{print $1}'|sort|uniq -c|sort -nr|head -10

 

4一、分析 2015/8/15 到 2015/8/16 訪問」/index.php?g=Member&m=Public&a=sendValidCode」的IP倒序排列

cat log_file | egrep '15/Aug/2015|16/Aug/2015' | awk '{if($7 == "/index.php?g=Member&m=Public&a=sendValidCode") print $1,$7}'|sort|uniq -c|sort -nr

4二、($7~/.php/) $7裏面包含.php的就輸出,本句的意思是最耗時的一百個PHP頁面

cat log_file |awk '($7~/.php/){print $NF " " $1 " " $4 " " $7}'|sort -nr|head -100

 

4三、列出最最耗時的頁面(超過60秒的)的以及對應頁面發生次數

cat access.log |awk '($NF > 60 && $7~/.php/){print $7}'|sort -n|uniq -c|sort -nr|head -100

 

4四、統計網站流量(G)

cat access.log |awk '{sum+=$10} END {print sum/1024/1024/1024}'

 

4五、統計404的鏈接

awk '($9 ~/404/)' access.log | awk '{print $9,$7}' | sort

4六、統計http status

cat access.log |awk '{counts[$(9)]+=1}; END {for(code in counts) print code, counts[code]}' cat access.log |awk '{print $9}'|sort|uniq -c|sort -rn

4七、每秒併發

watch "awk '{if($9~/200|30|404/)COUNT[$4]++}END{for( a in COUNT) print a,COUNT[a]}' log_file|sort -k 2 -nr|head -n10"

 

4八、帶寬統計

cat apache.log |awk '{if($7~/GET/) count++}END{print "client_request="count}'

4九、找出某天訪問次數最多的10個IP

cat /tmp/access.log | grep "20/Mar/2011" |awk '{print $3}'|sort |uniq -c|sort -nr|head

50、當天ip鏈接數最高的ip都在幹些什麼

cat access.log | grep "10.0.21.17" | awk '{print $8}' | sort | uniq -c | sort -nr | head -n 10

 

5一、小時單位裏ip鏈接數最多的10個時段

awk -vFS="[:]" '{gsub("-.*","",$1);num[$2" "$1]++}END{for(i in num)print i,num[i]}' log_file | sort -n -k 3 -r | head -10

5二、找出訪問次數最多的幾個分鐘

awk '{print $1}' access.log | grep "20/Mar/2011" |cut -c 14-18|sort|uniq -c|sort -nr|hea

 

5三、取5分鐘日誌

if [ $DATE_MINUTE != $DATE_END_MINUTE ] ;then #

則判斷開始時間戳與結束時間戳是否相等

START_LINE=sed -n "/$DATE_MINUTE/=" $APACHE_LOG|head -n1#若是不相等,則取出開始時間戳的行號,與結束時間戳的行號

查看tcp的連接狀態

netstat -nat |awk '{print $6}'|sort|uniq -c|sort -rn netstat -n | awk '/^tcp/ {++S[$NF]};END {for(a in S) print a, S[a]}' netstat -n | awk '/^tcp/ {++state[$NF]}; END {for(key in state) print key,"    ",state[key]}' netstat -n | awk '/^tcp/ {++arr[$NF]};END {for(k in arr) print k,"    ",arr[k]}' netstat -n |awk '/^tcp/ {print $NF}'|sort|uniq -c|sort -rn netstat -ant | awk '{print $NF}' | grep -v '[a-z]' | sort | uniq -c netstat -ant|awk '/ip:80/{split($5,ip,":");++S[ip[1]]}END{for (a in S) print S[a],a}' |sort -n netstat -ant|awk '/:80/{split($5,ip,":");++S[ip[1]]}END{for (a in S) print S[a],a}' |sort -rn|head -n 10 awk 'BEGIN{printf ("http_code    count_num")}{COUNT[$10]++}END{for (a in COUNT) printf a"        "COUNT[a]" "}'

5四、查找請求數前20個IP(經常使用於查找攻來源):

netstat -anlp|grep 80|grep tcp|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -n20 netstat -ant |awk '/:80/{split($5,ip,":");++A[ip[1]]}END{for(i in A) print A[i],i}' |sort -rn|head -n20

 

5五、用tcpdump嗅探80端口的訪問看看誰最高

tcpdump -i eth0 -tnn dst port 80 -c 1000 | awk -F"." '{print $1"."$2"."$3"."$4}' | sort | uniq -c | sort -nr |head -20

5六、根據端口列進程

netstat -ntlp | grep 80 | awk '{print $7}' | cut -d/ -f1

5七、Linux命令分析當前的連接情況

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

 

5八、watch "netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'"# 經過watch能夠一直監控

LAST_ACK 5 #關閉一個TCP鏈接須要從兩個方向上分別進行關閉,雙方都是經過發送FIN來表示單方向數據的關閉,當通訊雙方發送了最後一個FIN的時候,發送方此時處於LAST_ACK狀態,當發送方收到對方的確認(Fin的Ack確認)後才真正關閉整個TCP鏈接;

SYN_RECV 30 # 表示正在等待處理的請求數;

ESTABLISHED 1597 # 表示正常數據傳輸狀態;

FIN_WAIT1 51 # 表示server端主動要求關閉tcp鏈接;

FIN_WAIT2 504 # 表示客戶端中斷鏈接;

TIME_WAIT 1057 # 表示處理完畢,等待超時結束的請求數;

5九、

60、

 

 

6一、

6二、

6三、

 

6四、

6五、

6六、

 

6七、

 

6八、

6九、

70、

 

參考連接 : 

10分鐘學會 linux awk命令 : https://mp.weixin.qq.com/s/a8inpw8TrEOw7rxVgYQDwg

SHELL——awk報告生成器(基礎用法) : https://blog.csdn.net/qq_42036824/article/details/85225853

相關文章
相關標籤/搜索