SElinux

awk介紹

  • awk:Aho, Weinberger, Kernighan,報告生成器,格式化文本輸出
  • 有多種版本:New awk(nawk),GNU awk( gawk)
  • gawk:模式掃描和處理語言
  • 基本用法
awk [options] 'program' var=value file…
awk [options] -f programfile var=value file…
awk [options] 'BEGIN{ action;… } pattern{ action;… } END{action;… }' file ...
BEGIN是文件一行沒有讀進來的時候要做的事情或要執行的動作
END當整個文件都處理完之後,要執行的動作比
pattern是每一行要處理的動作
awk 程序通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊,共3部分組成
program通常是被單引號或雙引號中

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

awk語言


  • 基本格式:awk [options] ‘program’ file…
  • program=pattern{action statements;..}
  • pattern和action:
    • pattern部分決定動作語句何時觸發及觸發事件BEGIN,END
    • action statements對數據進行處理,放在{}內指明print, printf
  • 分割符、域和記錄
    • awk執行時,由分隔符分隔的字段(域)標記1, 2..n 0爲所有域,注意:和shell中變量$符含義不同
    • 文件的每一行稱爲記錄,默認是以回車換行爲分隔符,當然也有可能用其它分隔符來標識記錄的分隔
    • 省略action,則默認執行 print $0 的操作
  • 總結:awk是讀入一行,會按照定義的分隔符,切割成字段,分隔符可以用-F來定義,分隔完後這些字段會有名字比如第一個字段是12 2,3, 後面跟第幾個字段,也可以當1 3字段,也可循環從1 1爲大於100時,就取中間$3,如果小於100則不做處理,讀取下一行

範例
mark

  • 如果awk不寫program則是整行都處理,所以會讀入一行執行一個print這個動作
    mark
  • awk默認是讀取標準輸出的,所以我們可以用管道傳給awk
  • mark
    mark
  • 這裏一定要注意,只要是字符串一定要拿雙引號引起來
  • 也可以做數字運算,數字不用加雙引號
    mark
  • 取出/etc/passwd文件的第3列
  • mark
  • 取出磁盤利用率也是很方便的,awk默認是以空格爲分隔符的。也可取多個字段,也可自定義格式
    mark
  • [root@centos6 app]# df | grep /dev/sd| awk '{print $1,$5}'  
    /dev/sda2 10%
    /dev/sda3 1%
    /dev/sda1 4%
    [root@centos6 app]# df | grep /dev/sd| awk '{print $1"===="$5}'  
    /dev/sda2====10%
    /dev/sda3====1%
    /dev/sda1====4%

    awk工作原理

    • 第一步:執行BEGIN{action;… }語句塊中的語句
    • 第二步:從文件或標準輸入(stdin)讀取一行,然執行pattern{action;… }語句塊,它逐行掃描文件,從第一行到後一行重複這個過程,直到文件全部被讀取完畢。
    • 第三步:當讀至輸入流末尾時,執行END{action;…}語句塊
    • BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中
    • END語句塊在awk從輸入流中讀取完所有的行之後即被執行,比如打印所有行的分析結果這類信息彙總都是在END語句塊中完成,它也是一個可選語句塊
    • pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認執行{ print } ,即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊

    awk格式

    • print格式: print item1, item2, …
    • 要點
      1. 逗號分隔符
      2. 輸出的各item可以字符串,也可以是數值;當前記錄的字段、變量或awk的表達式
      3. 如省略item,相當於print $0
    • 示列
    awk '{print "hello,awk"}'
    awk –F: '{print}' /etc/passwd
    awk –F: '{print "wang"}' /etc/passwd
    awk –F: '{print $1}' /etc/passwd
    awk –F: '{print $0}' /etc/passwd
    awk –F: '{print $1"\t"$3}' /etc/passwd
    tail –3 /etc/fstab |awk '{print $2,$4}'

    awk變量

    • 變量:內置和自定義變量
    • 在使用變量時,前面加-v表示對變量賦值
    • FS:輸入字段分隔符,默認爲空白字符
    awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
    awk –F: '{print $1,$3,$7}' /etc/passwd
    這兩種寫法是等價的
    因爲FS是一個變量,所有我們可以引用這個變量,而-F是一個選項,不能被引用
    [root@centos6 app]# awk -v FS=":" '{print $1,FS,$4}' /etc/passwd
    root : 0
    bin : 1
    daemon : 2
    adm : 4
    lp : 7
    sync : 0
    shutdown : 0
    halt : 0
    mail : 12
    uucp : 14
    operator : 0
    games : 100
    gopher : 30
    ftp : 50
    nobody : 99
    dbus : 81
    usbmuxd : 113
    FS也可以引用bash變量
    [root@centos6 app]# i=":" ; awk -v FS="$i" '{ print $1,FS,$3 }' /etc/passwd
    root : 0
    bin : 1
    daemon : 2
    adm : 3
    lp : 4
    sync : 5
    shutdown : 6
    halt : 7
    mail : 8
    -F也是可以調用shell變量的,只是裏面不能使用了
    [root@centos6 app]# i=":" ; awk -F "$i" '{ print $1,:,$3 }' /etc/passwd
    • OFS:輸出字段分隔符,默認爲空白字符
    awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd
    逗號默認輸出是空格爲分隔符,我們也可以定義顯示的分隔符
    [root@centos6 app]# awk -v FS=":" -v OFS="+" '{print $1,$3}' /etc/passwd
    root+0
    bin+1
    daemon+2
    adm+3
    lp+4
    sync+5
    shutdown+6
    halt+7
    mail+8
    • RS:輸入記錄分隔符,指定輸入時的換行符,默認是以回車換行爲一行的分隔符。當然我們也可以指定行分隔符
    awk -v RS=' ' '{print }' /etc/passwd
    比如,
    vim f1.txt
    1 2 3;4 5 6;7
    8 9
    如果我們以分號爲分隔符,這這裏就是3行記錄
    [root@centos6 app]# awk -v RS=";" '{print $2}' f1.txt 
    2
    5
    8
    默認是以空白符分隔字段,我們打印第2個字段所有是258是三行記錄
    ===================
    [root@centos6 app]# cat f2 
    a
    b
    c dd
    ff
    gg aaa
    qq
    ww
    eee ccc
    這文件如果我們以空格爲記錄分隔符,取第1個字段和第2個字段的結果是什麼
    [root@centos6 app]# awk -v RS=" " '{print $1,$2}' f2
    a b
    dd ff
    aaa qq
    ccc 
    結果是這樣的,所有回車換行並不是空白符
    • ORS:輸出記錄分隔符,輸出時用指定符號代替換行符
    • 默認輸出的時候是以回車換行爲分隔符
    awk -v RS=' ' -v ORS='###''{print }' /etc/passwd
    [root@centos6 app]# awk -v ORS="====" -v RS=" " '{print $1,$2}' f2
    a b====dd ff====aaa qq====ccc ====[root@centos6 app]# 
    • NF:字段數量
    awk -F: '{print NF}' /etc/fstab,引用內置變量不用$
    awk -F: '{print $(NF-1)}' /etc/passwd
    [root@centos6 app]# awk -F : '{print NF}' /etc/passwd
    7
    7
    7
    7
    7
    [root@centos6 app]# awk -F : '{print $NF}' /etc/passwd   $NF表示最後一個字段
    /bin/bash
    /sbin/nologin
    /sbin/nologin
    /sbin/nologin
    /sbin/nologin
    [root@centos6 app]# awk -F : '{print $(NF-1)}' /etc/passwd  
    /root
    [root@centos6 app]# df |awk '{print $(NF-1)}'|awk -F % '{print $1}'
    Mounted
    10
    1
    1
    4
    100
    [root@centos6 app]# 
    • NR:記錄號,行號,空行也算
    awk '{print NR}' /etc/fstab ; awk END'{print NR}' /etc/fstab
    [root@centos6 app]# awk '{print NR $0}' /etc/fstab 
    1
    2#
    3# /etc/fstab
    4# Created by anaconda on Tue Nov  7 15:42:36 2017
    5#
    6# Accessible filesystems, by reference, are maintained under '/dev/disk'
    7# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
    8#
    9UUID=03352018-7cef-4ee3-9a05-b0833b67da19 /                       ext4    defaults        1 1
    10UUID=0bd51fa6-f577-427a-b0b2-1cb8a631ac16 /app                    ext4    defaults        1 2
    11UUID=bbfd63dd-da18-4ac9-affd-4724c571db21 /boot                   ext4    defaults        1 2
    12UUID=a8c19a79-3c21-4aa4-a648-27a069f25bde swap                    swap    defaults        0 0
    也可以後面跟多個文件,awk會認爲把多個文件當成一個文件開始計算行號
    [root@centos6 app]# awk '{print NR $0}' /etc/fstab  /etc/issue
    1
    2#
    3# /etc/fstab
    4# Created by anaconda on Tue Nov  7 15:42:36 2017
    5#
    6# Accessible filesystems, by reference, are maintained under '/dev/disk'
    7# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
    8#
    9UUID=03352018-7cef-4ee3-9a05-b0833b67da19 /                       ext4    defaults        1 1
    10UUID=0bd51fa6-f577-427a-b0b2-1cb8a631ac16 /app                    ext4    defaults        1 2
    11UUID=bbfd63dd-da18-4ac9-affd-4724c571db21 /boot                   ext4    defaults        1 2
    12UUID=a8c19a79-3c21-4aa4-a648-27a069f25bde swap                    swap    defaults        0 0
    13tmpfs                   /dev/shm                tmpfs   defaults        0 0
    14devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
    15sysfs                   /sys                    sysfs   defaults        0 0
    16proc                    /proc                   proc    defaults        0 0
    17/dev/cdrom    /mnt    iso9660         defaults        0       0
    18CentOS release 6.9 (Final)
    19Kernel \r on an \m
    20
    • FNR:各文件分別計數,記錄號
    • 因爲NR是會把多個文件當成一個統計,所有FNR會把文件單獨統計
    awk '{print FNR}' /etc/fstab /etc/inittab
    [root@centos6 app]# awk '{print FNR $0}' /etc/fstab /etc/issue
    1
    2#
    3# /etc/fstab
    4# Created by anaconda on Tue Nov  7 15:42:36 2017
    5#
    6# Accessible filesystems, by reference, are maintained under '/dev/disk'
    7# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
    8#
    9UUID=03352018-7cef-4ee3-9a05-b0833b67da19 /                       ext4    defaults        1 1
    10UUID=0bd51fa6-f577-427a-b0b2-1cb8a631ac16 /app                    ext4    defaults        1 2
    11UUID=bbfd63dd-da18-4ac9-affd-4724c571db21 /boot                   ext4    defaults        1 2
    12UUID=a8c19a79-3c21-4aa4-a648-27a069f25bde swap                    swap    defaults        0 0
    13tmpfs                   /dev/shm                tmpfs   defaults        0 0
    14devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
    15sysfs                   /sys                    sysfs   defaults        0 0
    16proc                    /proc                   proc    defaults        0 0
    17/dev/cdrom    /mnt    iso9660         defaults        0       0
    1CentOS release 6.9 (Final)
    2Kernel \r on an \m
    3
    • FILENAME:顯示當前文件名
    awk '{print FILENAME}' /etc/fstab
    [root@centos6 app]# awk '{print FILENAME,$0}' /etc/issue 
    /etc/issue CentOS release 6.9 (Final)
    /etc/issue Kernel \r on an \m
    /etc/issue 
    • ARGC:命令行參數的個數
    awk '{print ARGC}' /etc/fstab /etc/inittab
    awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
    [root@centos6 app]# awk '{print ARGC}' /etc/fstab /etc/issue    
    3
    3
    3
    3
    3
    • ARGV:數組,保存的是命令行所給定的各參數
    awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/inittab
    awk 'BEGIN {print ARGV[1]}' /etc/fstab /etc/inittab
    [root@centos6 app]# awk '{print ARGV[0]}' /etc/fstab /etc/issue  
    awk
    awk
    awk
    awk
    • 自定義變量(區分字符大小寫)
      1. -v var=value
      2. 在program中直接定義
      3. 變量是先定義在調用
    • 示例
    awk -v test='hello gawk' '{print test}' /etc/fstab
    awk -v test='hello gawk' 'BEGIN{print test}'
    awk 'BEGIN{test="hello,gawk";print test}'
    awk –F:'{sex="male";print $1,sex,age;age=18}' /etc/passwd
    ======也可將常用的程序寫到文件中用-f調用======
    cat awkscript 
    {print script,$1,$2}
    awk -F: -f awkscript script="awk" /etc/passwd
    [root@centos6 app]# cat awk.txt 
    {user="usernam";uid="uid";print user"="$1,uid"="$3}
    [root@centos6 app]# awk -F: -f awk.txt /etc/passwd
    usernam=root uid=0
    usernam=bin uid=1
    usernam=daemon uid=2
    usernam=adm uid=3
    usernam=lp uid=4
    ==========
    [root@centos6 app]# awk -v user="username" -v uid="uid" -F: '{print user"="$1,uid"="$3}' /etc/passwd
    username=root uid=0
    username=bin uid=1
    username=daemon uid=2
    username=adm uid=3
    username=lp uid=4
    username=sync uid=5
    username=shutdown uid=6
    [root@centos6 app]# awk  -v uid="uid" -F: '{user="username";print user"="$1,uid"="$3}' /etc/passwd     //也可以在程序裏定義變量,在程序裏定義變量就不能調用shell裏的變量               
    username=root uid=0
    username=bin uid=1
    username=daemon uid=2
    username=adm uid=3
    username=lp uid=4
    username=sync uid=5
    username=shutdown uid=6
    username=halt uid=7
    userame=mail uid=8
    username=uucp uid=10
    [root@centos6 app]# u=username; awk -v user=$u -v uid=uid -F: '{print user"="$1,uid"="$3}' /etc/passwd  
    username=root uid=0
    username=bin uid=1
    username=daemon uid=2
    username=adm uid=3

    printf命令


    • 格式化輸出:printf “FORMAT”, item1, item2, …
      1. 必須指定FORMAT
      2. 不會自動換行,需要顯式給出換行控制符,\n
      3. FORMAT中需要分別爲後面每個item指定格式符
      4. 格式和數據要以逗號隔開

    格式符:與item一一對應
    %c: 顯示字符的ASCII碼
    %d, %i: 顯示十進制整數
    %e, %E:顯示科學計數法數值
    %f:顯示爲浮點數
    %g, %G:以科學計數法或浮點形式顯示數值
    %s:顯示字符串
    %u:無符號整數
    %%: 顯示%自身
  • 修飾符
  • #[.#]:第一個數字控制顯示的寬度;第二個#表示小數點後精度,%3.1f
    -: 左對齊(默認右對齊) %-15s
    +:顯示數值的正負符號 %+d

    printf示例

    awk -F: '{printf "%s",$1}' /etc/passwd
    awk -F: '{printf "%s\n",$1}' /etc/passwd
    awk -F: '{printf "%-20s %10d\n",$1,$3}' /etc/passwd
    awk -F: '{printf "Username: %s\n",$1}' /etc/passwd
    awk -F: '{printf “Username: %s,UID:%d\n",$1,$3}' /etc/passwd
    awk -F: '{printf "Username: %15s,UID:%d\n",$1,$3}' /etc/passwd
    awk -F: '{printf "Username: %-15s,UID:%d\n",$1,$3}' /etc/passwd
    [root@centos6 app]# awk -F: '{printf "%s:%d\n",$1,$3}' /etc/passwd
    root:0
    bin:1
    daemon:2
    adm:3
    lp:4
    sync:5
    shutdown:6
    halt:7
    mail:8
    uucp:10
    operator:11
    [root@centos6 app]# awk -F: '{printf "%-30s%d\n",$1,$3}' /etc/passwd 
    root                          0
    bin                           1
    daemon                        2
    adm                           3
    lp                            4
    sync                          5
    shutdown                      6
    halt                          7
    [root@centos6 app]# awk -F: '{printf "%-30s| %d\n",$1,$3}' /etc/passwd
    root                          | 0
    bin                           | 1
    daemon                        | 2
    adm                           | 3
    lp                            | 4
    sync                          | 5
    shutdown                      | 6
    halt                          | 7
    
    [root@centos6 app]# awk -v n=123.4567 '{printf "%8.4f\n",n }'  /etc/fstab  //這裏n的值加小數點一共8位,所有我們第一個8是總長度,小數點之後的是4位
    123.4567
    123.4567
    123.4567
    123.4567
    123.4567
    [root@centos6 app]# awk -v n=123.4567 '{printf "%8.3f\n",n }' /etc/fstab  這個意思是小數點之後是3位說以最後一位7被四捨五入了,但是前面多一個空格,代表一共是8位
     123.457
     123.457
     123.457
     123.457
     123.457
     123.457
     123.457
    因爲這裏打印多行是文件有幾行就打印幾行,我們可以用BEGIN,可以不用跟文件就打印一次
    [root@centos6 app]# awk -v n=123.4567 'BEGIN{printf "%8.3f\n",n }'
     123.457
    [root@centos6 app]# awk -v n=123.4567 'BEGIN{printf "%10.3f\n",n }' 
       123.457

    操作符

    • 算術操作符
    x+y, x-y, x*y, x/y, x^y, x%y
    [root@centos6 app]# awk -v n=10 -v m=3 'BEGIN{print n%m}'
    1

    -x: 轉換爲負數
    +x: 轉換爲數值
    - 字符串操作符:沒有符號的操作符,字符串連接
    - 賦值操作符

    =, +=, -=, *=, /=, %=, ^=
    ++, --
    [root@centos6 app]# awk -v n=10 -v m=3 'BEGIN{print m+=n}'
    13
    [root@centos6 app]# awk -v n=10 -v m=3 'BEGIN{print m+=n,m++,m}'  這個是m++是先讀取在自+
    13 13 14 
    [root@centos6 app]# awk -v n=10 -v m=3 'BEGIN{print m+=n,++m,m}'
    13 14 14
    下面兩語句有何不同
    awk 'BEGIN{i=0;print ++i,i}'
    [root@centos6 app]# awk 'BEGIN{i=0;print ++i,i}'
    1 1
    awk 'BEGIN{i=0;print i++,i}'
    [root@centos6 app]# awk 'BEGIN{i=0;print i++,i}'
    0 1
    • 比較操作符
    ==, !=, >, >=, <, <=
    • 模式匹配符
    ~:左邊是否和右邊匹配包含只要包含就匹配 !~:是否不匹配
    • 支持擴展的正則表達式,一般正則表達式都要放在兩個斜線之前,或者雙引號
    awk –F: '$0 ~ /root/{print $1}' /etc/passwd
    awk '$0~“^root"' /etc/passwd
    awk '$0 !~ /root/' /etc/passwd
    awk –F: '$3==0' /etc/passwd
    [root@centos6 app]# awk '$0~"^root"' /etc/passwd   awk如果不寫花括號,模式是print $0打印整行
    root:x:0:0:root:/root:/bin/bash
    [root@centos6 app]# awk '$0 ~ /^bin/' /etc/passwd   正則表達式是要放在兩個斜線之前的
    bin:x:1:1:bin:/bin:/sbin/nologin
    [root@centos6 app]# awk -F: '$3==0' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    [root@centos6 app]# awk -F: '$3>=500' /etc/passwd  這裏相當於每讀入一行就判斷
    nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
    guo:x:500:500::/home/guo:/bin/bash
    [root@centos6 app]# 
    ============================
    [root@centos6 app]# awk  -v i= "i" /etc/issue   i沒有賦值是假
    [root@centos6 app]# awk  -v i="" "i" /etc/issue 這樣也是假
    [root@centos6 app]# awk  -v i=0 "i" /etc/issue   i等於0也是假
    [root@centos6 app]# awk  -v i=" " "i" /etc/issue  i等於空是真,打印全部內容
    CentOS release 6.9 (Final)
    Kernel \r on an \m
    只要不是0,空,或沒有定義,都算真,負數也算真
    • 當pattern條件爲真的時候執行{}花括號裏的內容
    • 邏輯操作符:與&&,或||,非!
    awk –F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
    awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
    awk -F: '!($3==0) {print $1}' /etc/passwd
    awk -F: '!($3>=500) {print $3}' /etc/passwd
    [root@centos6 app]# awk -F: -v i=10 'i' /etc/issue
    CentOS release 6.9 (Final)
    Kernel \r on an \m
    
    [root@centos6 app]# awk -F: -v i=10 '!i' /etc/issue
    [root@centos6 app]# awk -F: -v i=10 '{print i}' /etc/issue  
    10
    10
    10
    [root@centos6 app]# awk -F: -v i=10 '{print !i}' /etc/issue
    0
    0
    0
    假取反就是真
    [root@centos6 app]# awk '{i=0;print !i++,i}' /etc/issue 先取反打印,然後在運算
    1 1
    1 1
    1 1
    [root@centos6 app]# awk '{i=-1;print !i++,i}' /etc/issue 
    0 0
    0 0
    0 0
    
    [root@centos6 app]# awk '{i=0;print !++i,i}' /etc/issue     先運算++,得出的數值在取反   
    0 1
    0 1
    0 1
    [root@centos6 app]# awk '{i=-1;print !++i,i}' /etc/issue 
    1 0
    1 0
    1 0
    • 函數調用: function_name(argu1, argu2, …)
    • 條件表達式(三目表達式)
      • selector?if-true-expression:if-false-expression
      • 用?號,冒號隔成三段
      • 其中?號是條件判斷,如果條件爲真則執行?號後面的語句,如果爲假則執行冒號後面的語句
    awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd
    [root@centos6 app]# awk -F: '{$3>=500?usertype="common user":usertype="sysuser" ;printf "%15s %30s %d \n", usertype,$1,$3 }' /etc/passwd
            sysuser                           root 0 
            sysuser                            bin 1 
            sysuser                         daemon 2 
            sysuser                            adm 3 
            sysuser                             lp 4 
            sysuser                           sync 5 
            sysuser                       shutdown 6 
            sysuser                           halt 7 
            sysuser                           mail 8 
            sysuser                           uucp 10 
            sysuser                       operator 11 
            sysuser                          games 12 
            sysuser                         gopher 13 
            sysuser                            ftp 14 
            sysuser                         nobody 99 
            sysuser                           dbus 81 
            sysuser                        usbmuxd 113 
            sysuser                            rpc 32 
            sysuser                          rtkit 499 
            sysuser                  avahi-autoipd 170 
            sysuser                           vcsa 69 
            sysuser                           abrt 173 
            sysuser                        rpcuser 29 
        common user                      nfsnobody 65534 
            sysuser                      haldaemon 68 

    awk PATTERN

    • PATTERN:根據pattern條件,過濾匹配的行,再做處理
      1. 如果未指定:空模式,匹配每一行,所有都匹配
      2. /regular expression/:僅處理能夠模式匹配到的行,需要用/ /裏面可以寫正則表達式
        • awk ‘/^UUID/{print $1}’ /etc/fstab 也可以不用~直接寫正則表達式
        • awk ‘!/^UUID/{print $1}’ /etc/fstab
      3. relational expression: 關係表達式,結果爲“真”纔會被處理
        • 真:結果爲非0值,非空字符串
        • 假:結果爲空字符串或0值
    awk -F: 'i=1;j=1{print i,j}' /etc/passwd
    awk '!0' /etc/passwd ; awk '!1' /etc/passwd
    awk –F: '$3>=1000{print $1,$3}' /etc/passwd
    awk -F: '$3<1000{print $1,$3}' /etc/passwd
    awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
    awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
    取奇數行和偶數行
    [root@centos6 app]# seq 10 | sed -n '1~2p'
    1
    3
    5
    7
    9
    [root@centos6 app]# seq 10 | sed -n '2~2p'
    2
    4
    6
    8
    10
    用awk來取奇數和偶數行
    [root@centos6 app]# seq 10 | awk 'i=!i'   因爲i爲假,然後對i取反就是真那麼第一行就是真打印第一行,當讀入第2行時i已經是真了,所以i取反爲假就不打印第2行
    1
    3
    5
    7
    9
    [root@centos6 app]# seq 10 |awk -v i=11 'i=!i'
    2
    4
    6
    8
    10
    [root@centos6 app]# seq 10 |awk  '!(i=!i)'       
    2
    4
    6
    8
    10
    1. line ranges:行範圍
    startline,endline:/pat1/,/pat2/ 不支持直接給出數字格式
    awk -F: '/^root\>/,/^nobody\>/{print $1}' /etc/passwd
    awk -F: '(NR>=10&&NR<=20){print NR,$1}' /etc/passwd
    [root@centos6 app]# awk '/^f/,/^r/' /etc/passwd   首先找到第一pat1是開始顯示,一直找到pat2結束
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    nobody:x:99:99:Nobody:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
    rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
    sed如何顯示從第幾行到第幾行
    [root@centos6 app]# seq 10 | sed -n '2,5p'
    2
    3
    4
    5
    awk如何顯示從第幾行到第幾行
    [root@centos6 app]# seq 10 | awk 'NR>=2&&NR<=5'
    2
    3
    4
    5

    5.BEGIN/END模式

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

    示例

    awk -F : 'BEGIN {print "USER USERID"} {print $1":"$3}END{print "end file"}' /etc/passwd
    awk -F : '{print "USER USERID“;print $1":"$3} END{print"end file"}' /etc/passwd
    awk -F: 'BEGIN{print " USER UID \n---------------"}{print $1,$3}' /etc/passwd
    awk -F: 'BEGIN{print " USER UID \n---------------"}{print $1,$3}'END{print "=============="} /etc/passwd
    seq 10 |awk 'i=0'
    seq 10 |awk 'i=1'
    seq 10 | awk 'i=!i'
    seq 10 | awk '{i=!i;print i}'
    seq 10 | awk '!(i=!i)'
    seq 10 |awk -v i=1 'i=!i
    [root@centos6 app]# awk -F: 'BEGIN{printf "USERNAEM                        UDI\n=================================\n"}{printf "%-30s %d\n",$1,$3}' /etc/passwd    
    USERNAEM                        UDI
    =================================
    root                           0
    bin                            1
    daemon                         2
    adm                            3
    lp                             4
    sync                           5
    shutdown                       6
    halt                           7
    mail                           8
    uucp                           10
    operator                       1
    guo                            500
    [root@centos6 app]# awk -F: 'BEGIN{printf "=================================\nUSERNAEM                     UDI\n=================================\n"}{printf "%-30s %d\n",$1,$3}' /etc/passwd   
    =================================
    USERNAEM                     UDI
    =================================
    root                           0
    bin                            1
    daemon                         2
    adm                            3
    lp                             4
    sync                           5
    shutdown                       6
    halt                           7
    mail                           8
    uucp                           10
    operator                       11
    [root@centos6 app]# awk -F: 'BEGIN{printf "=================================\nUSERNAEM                    | UDI\n=================================\n"}{printf "|%-30s | %d\n=================================\n",$1,$3}' /etc/passwd
    =================================
    USERNAEM                    | UDI
    =================================
    |root                           | 0
    =================================
    |bin                            | 1
    =================================
    |daemon                         | 2
    =================================
    |adm                            | 3
    =================================
    |lp                             | 4
    =================================
    |sync                           | 5
    

    awk action

    • 常用的action分類
      1. Expressions:算術,比較表達式等
      2. Control statements:if, while等
      3. Compound statements:組合語句
      4. input statements
      5. output statements:print等

    awk控制語句

    • { statements;… } 組合語句,用分號隔開
    • if(condition) {statements;…}
    • if(condition) {statements;…} else {statements;…}
    • while(conditon) {statments;…}
    • do {statements;…} while(condition)
    • for(expr1;expr2;expr3) {statements;…}
    • break
    • continue
    • delete array[index]
    • delete array
    • exit

    awk控制語句if-else

    語法
    if(condition){statement;…}[else statement]
    if(condition1){statement1}else if(condition2){statement2} else{statement3}
    - 使用場景:對awk取得的整行或某個字段做條件判斷
    示例

    awk -F: '{if($3>=1000)print $1,$3}' /etc/passwd  //如果是單一的一條語句可以不用大括號擴起來
    awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
    awk '{if(NF>5) print $0}' /etc/fstab
    awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else{printf "root or Sysuser: %s\n",$1}}' /etc/passwd
    awk -F: '{if($3>=1000) printf "Common user: %s\n",$1;else printf "root or Sysuser: %s\n",$1}' /etc/passwd 
    df -h|awk -F% '/^\/dev/{print $1}'|awk '$NF>=80{print $1,$5}'
    awk 'BEGIN{ test=100;if(test>90){print "very good"} else if(test>60){ print "good"}else{print "no pass"}}'
    [root@centos6 app]# awk -F: '{if ($3>=500){usertype="common user" ;print usertype,$1,$3}}' /etc/passwd
    common user nfsnobody 65534
    common user guo 500
    取出分區利用率
    [root@centos6 app]# df | awk '/^\/dev\/sd/{print $1,$(NF-1)}'
    /dev/sda2 10%
    /dev/sda3 1%
    /dev/sda1 4%
    [root@centos6 app]# df | awk '{if($0~/^\/dev\/sd/)print $1,$(NF-1)}'
    /dev/sda2 10%
    /dev/sda3 1%
    /dev/sda1 4%
    取當分區利用率大於多少時取出對應的設備名
    [root@centos6 app]# df | awk -F% '/^\/dev\/sd/{print $(NF-1)}'|awk  '{if($NF>=10)print $1,$NF}'    
    /dev/sda2 10
    也可以使用用多個分隔符
    [root@centos6 app]# df | awk -F "[ %]+" '/^\/dev\/sd/{print $1,$5}'
    /dev/sda2 10
    /dev/sda3 1
    /dev/sda1 4

    awk控制語句while循環

    • while循環
    • 語法:while(condition){statement;…}
    • 條件“真”,進入循環;條件“假”,退出循環
    • 使用場景
      • 對一行內的多個字段逐一類似處理時使用,對字段進行循環
      • 對數組中的各元素逐一處理時使用
      • length($1)這是一個函數,統計某個字段有多長
    [root@centos6 app]# awk -F: '{print $1,length($1)}' /etc/passwd
    root 4
    bin 3
    daemon 6
    adm 3
    lp 2
    sync 4
    shutdown 8
    halt 4
    mail 4
    uucp 4
    operator 8
    games 5
    gopher 6
    ftp 3
    在shell中如何判斷字符數
    [root@centos6 app]# v=hahah
    [root@centos6 app]# echo ${#v}
    5
    判斷root這一行每個字段各是多少個字符
    [root@centos6 app]# awk -F: '/^root/{i=1;while(i<=NF){print $i ,length($i);i++}}' /etc/passwd
    root 4
    x 1
    0 1
    0 1
    root 4
    /root 5
    /bin/bash 9
    如何用awk語句從1加到100之和  
    [root@centos6 app]# awk 'BEGIN{i=1;sum=0;while(i<=100){sum+=i;i++}print sum}'
    5050
    [root@centos6 app]# awk 'BEGIN{i=1;sum=0;do{sum+=i;i++}while(i<=100)print sum}'
    5050
    [root@centos6 app]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++)sum+=i;print sum}' 
    5050
    用seq計算1100之和
    [root@centos6 app]# seq -s+ 1 100 |bc
    5050

    示例

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

    awk控制語句do-while循環

    • 語法:do {statement;…}while(condition)d
    • 意義:無論真假,至少執行一次循環體
      示例
     awk 'BEGIN{ total=0;i=0;do{total+=i;i++;}while(i<=100);print total}'

    awk控制語句for循環

    • for循環
    • 語法:for(expr1;expr2;expr3) {statement;…}
    • 常見用法
    for(variable assignment;condition;iteration process){for-body}
    • 特殊用法:能夠遍歷數組中的元素
      • 語法:for(var in array) {for-body}
        示例
    awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg

    性能比較

    • 測試中發現,awk的性能高於shell性能
    time (awk 'BEGIN{total=0;for(i=0;i<=10000;i++){total+=i;};print total;}') 
    time (total=0;for i in {1..10000};do total=$(($total+i));done;echo $total)
    time (for ((i=0;i<=10000;i++));do let total+=i;done;echo $total)
    time (seq –s ”+” 10000|bc)
    [root@centos6 app]# time awk 'BEGIN{sum=0;for(i=1;i<=10000000;i++)sum+=i;print sum}'
    50000005000000
    
    real    0m0.923s
    user    0m0.921s
    sys     0m0.002s
    這裏時間第一個時間表示一共使用多長時間
    第2個是用戶空間使用時間
    第3個系統使用空間
    

    awk控制語句switch語句

    • switch語句
    • 語法
    switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2;...; default: statementn}

    awk控制語句break和continue

    • break和continue
    awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
    awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}'
    • break [n]
    • continue [n]
    • next
      • 提前結束對本行處理而直接進入下一行處理(awk自身循環)
      • awk -F: ‘{if(3 1,$3}’ /etc/passwd
    [root@centos6 app]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2!=0)continue ;sum+=i}print sum}'  
    2550
    [root@centos6 app]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i}print sum}'
    1225
    只對奇數行進行處理
    [root@centos6 app]# awk -F: '{if($3%2!=1)next;print $1,$3}' /etc/passwd  
    bin 1
    adm 3
    sync 5
    halt 7
    operator 11
    gopher 13
    nobody 99

    awk數組

    • 關聯數組:array[index-expression]
    • index-expression
      1. 可使用任意字符串;字符串要使用雙引號括起來
      2. 如果某數組元素事先不存在,在引用時,awk會自動創建此元素,並將其值初始化爲”空串”
      3. 若要判斷數組中是否存在某元素,要使用“index in array”格式進行遍歷
        示例
    weekdays[“mon”]="Monday"
    awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}'
    awk '!arr[$0]++' dupfile
    awk '{!arr[$0]++;print $0, arr[$0]}' dupfile
    用awk把文件中重複的行去掉
    [root@centos6 app]# cat aaa 
    aaaa
    bbbb
    cccc
    aaaaaa
    aaaa
    bbbb
    ddddd
    aa
    ddddd
    [root@centos6 app]# awk '!arr[$0]++' aaa 
    aaaa
    bbbb
    cccc
    aaaaaa
    ddddd
    shell去重複行方法
    [root@centos6 app]# sort aaa | uniq
    aa
    aaaa
    aaaaaa
    bbbb
    cccc
    ddddd
    • awk ‘!arr[$0]++’ aaa
      • 因爲arr是一個數組,數組是多個變量的集合,要想在數組中標識一個變量,就要用數組名加下標(索引編號),我們這裏用文件的行來定義下標,arr是數組[$0],然後先取反因爲這個數組的變量是沒有賦值所以默認是假,但是取反就是真,如果是真就++,0++就是1 這裏會賦值爲1打印此行,當有一樣符下標時因爲上面已經賦值爲1了,取反就爲0,0是假不打印此行,然後在++
    • 若要遍歷數組中的每個元素,要使用for循環
    • for(var in array) {for-body}
    • 注意:var會遍歷array的每個索引
      示例
    awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
     netstat -tan | awk '/^tcp/{state[$NF]++}END
        {for(i in state) { print i,state[i]}}'
    awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}'
        /var/log/httpd/access_log
    [root@centos6 app]# netstat -nta | awk '/^tcp/{state[$NF]++}END{for(i in state){print i,state[i]}}' 
    ESTABLISHED 1
    LISTEN 11
    查找日誌中的ip鏈接數和對應ip
    [root@centos6 app]# awk '{ip[$1]++}END{for(i in ip){print i,ip[i]}}' access_log 
    172.18.56.3 159091
    192.168.27.6 4004
    172.18.0.100 24
    分析日誌中鏈接數大於1000次的ip並加入到IPtables中
    [root@centos6 app]# awk '{ip[$1]++}END{for(i in ip)if(ip[i]>1000){print i}}' access_log |while read l ;do iptables -A INPUT -s $l -j REJECT; done
    分析會話鏈接數前十個的ip
    [root@centos6 app]# ss -nt|awk '/^ESTAB/{print $NF}'|awk -F: '{print $1}'|sort|uniq -c | sort -nr | head -n3
    分析會話鏈接數前十個的ip並加入iptables中
    [root@centos6 app]# ss -nt|awk '/^ESTAB/{print $NF}'|awk -F: '{print $1}'|sort|uniq -c | sort -nr | head -n3 | while read coo ip;do iptables -A INPUT -s $ip -j REJECT;done
    • 數值處理
      • rand():返回0和1之間一個隨機數
    awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
    [root@centos6 app]# awk 'BEGIN{print rand()}'  //如果直接這樣寫會固定值不變,要想生成隨機數需要調用另一個函數srand()
    0.237788
    [root@centos6 app]# awk 'BEGIN{print rand()}'
    0.237788
    [root@centos6 app]# awk 'BEGIN{print rand()}'
    0.237788
    [root@centos6 app]# awk 'BEGIN{srand();print rand()}' 這樣就生成隨機數,
    0.434576
    [root@centos6 app]# awk 'BEGIN{srand();print rand()}'
    0.510123
    [root@centos6 app]# awk 'BEGIN{srand();print rand()*10}' 我們可以成*10或更大
    3.07812
    [root@centos6 app]# awk 'BEGIN{srand();print int(rand()*10)}'加上int就是取整數
    8
    [root@centos6 app]# awk 'BEGIN{srand();print int(rand()*100)}'
    77
    [root@centos6 app]# awk 'BEGIN{srand();print int(rand()*100)}'
    17
    • 字符串處理
      • length([s]):返回指定字符串的長度
      • sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並將第一個匹配的內容替換爲s
    echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
    [root@centos6 app]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'   sub默認只替代第一個匹配的
    2008-08:08 08:08:08
    [root@centos6 app]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$1)'   gsub會把整個字段都匹配,因爲默認是以空白符分隔所以2008:08:08是第一個字段
    2008-08-08 08:08:08
    [root@centos6 app]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'  可以用$0整行匹配
    2008-08-08 08-08-08
    - gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並全部替換爲s所表示的內容
    
    echo "2008:08:08 08:08:08" | awk ‘gsub(/:/,“-",$0)'
    - split(s,array,[r]):以r爲分隔符,切割字符串s,並將切割後的結果保存至array所表示的數組中,第一個索引值爲1,第二個索引值爲2,…
    
    netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}
        END{for (i in count) {print i,count[i]}}'
    [root@centos6 app]# echo "2008:01:02 03:04:05" | awk '{split($0,str,":")}END{for(i in str){print i,str[i]}}'  這是以冒號爲分隔符,生成一個數組str,是整行分割,str數組下標1的值是2008
    4 04
    5 05
    1 2008
    2 01
    3 02 03
    統計文件中每個單詞出現的次數
    [root@1234 ~]# awk '{for(i=1;i<=NF;i++)word[$i]++}END{for(i in word)print word[i],i}' /etc/profile | sort -nr
    13 #
    9 [
    8 then
    8 if
    如何用awk顯示男生,女的總成績,和平均值
    [root@1234 ~]# vim f1
    li   85  female
    guo 100 male
    zhang  90 male
    wang 99 female
    li   85  female
    [root@1234 ~]# awk '{if($3=="male"){mnum++;msun+=$2}else{fnun++;fsum+=$2}}END{printf "male:%d  %5.2f\nfemale:%d %5.2f\n",mnum,msun/mnum,fnun,fsum/fnun}' f1
    male:2  95.00
    female:2 92.00
    用數組的方法
    [root@1234 ~]# awk '{num[$3]++;sum[$3]+=$2}END{for(sex in num)print sex,num[sex],sum[sex]/num[sex]}' f1   
    female 2 92
    male 2 95

    awk函數

    • 自定義函數
      格式
    function name ( parameter, parameter, ... ) {
                statements
                return expression
    }
    ( parameter, parameter, ... ) 這裏面的表示是參數,位置參數

    示例

    cat fun.awk
    function max(v1,v2) {
            v1>v2?var=v1:var=v2
            return var
    }
    BEGIN{a=3;b=2;print max(a,b)}
    awk –f fun.awk
    這個函數表示max(v1,v2)是形式上的參數,是沒有任何賦值的,只是代表着位置參數,而BEGIN{a=3;b=2;print max(a,b)}a,b是實際的參數,形式的參數和實際的參數可以名字不一樣,但是數量上一定要相等。
    v1>v2?var=v1:var=v2  這是是要執行的程序
    return var :return這個必須要寫,要返回一個值
    文件裏的不用加單引號
    awk 用-f 調用這個函數
    [root@1234 ~]# vim fun.awk    
    function max(v1,v2) {
           v1>v2?var=v1:var=v2
            return var
    }
    BEGIN {a=3;b=2;print max(a,b)}
    [root@1234 ~]# awk -f fun.awk 
    3
    
    • 也可以不寫a=3;b=2;,不在文件中定義死,我們可以用-v來定義變量
    [root@1234 ~]# vim fun.awk 
    function max(v1,v2) {
           v1>v2?var=v1:var=v2
            return var
    }
    BEGIN {print max(a,b)}
    [root@1234 ~]# awk -v a=20 -v b=30 -f fun.awk 
    30                    

    awk中調用shell命令

    • system命令
    • 空格是awk中的字符串連接符,如果system中需要使用awk中的變量可以使用空格分隔,或者說除了awk的變量外其他一律用”“引用起來
    awk BEGIN'{system("hostname") }'
    awk 'BEGIN{score=100; system("echo your score is " score) }'
    [root@1234 ~]# awk 'BEGIN{system("hostname")}'
    1234
    • 這裏要注意一點的是用echo顯示變量時要注意幾點
      1. 因爲這裏定義的變量i是awk中定義的變量,如果想要用echo顯示出來需要放在引號外面
      2. echo後面一定要有空格,否則會保語法錯誤
    [root@1234 ~]# awk 'BEGIN{i=10;system("echo i ")}'
    i
    [root@1234 ~]# awk 'BEGIN{i=10;system("echo"i)}'   這裏的echo沒有空格所以報語法錯誤   
    sh: echo10: command not found
    [root@1234 ~]# awk 'BEGIN{i=10;system("echo "i)}'
    10

    awk腳本

    • 將awk程序寫成腳本,直接調用或執行
    [root@1234 ~]# vim fun.awk 
    #!/bin/awk -f      
    function max(v1,v2) {
           v1>v2?var=v1:var=v2
            return var
    }
    BEGIN {print max(a,b)}
    [root@1234 ~]# chmod +x fun.awk 
    [root@1234 ~]# ./fun.awk -v a=10 -v b=20
    20

    示例

    cat f1.awk
        {if($3>=1000)print $1,$3}
    awk -F: -f f1.awk /etc/passwd
    cat f2.awk
    #!/bin/awk –f
    #this is a awk script
    {if($3>=1000)print $1,$3}
    # chmod +x f2.awk
    f2.awk –F: /etc/passwd

    向awk腳本傳遞參數


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

    示例

    cat test.awk
    #!/bin/awk –f
    {if($3 >=min && $3<=max)print $1,$3}
    chmod +x test.awk
    test.awk -F: min=100 max=200 /etc/passwd
    發表評論
    所有評論
    還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
    相關文章