awk從入門至放棄

什麼是awk?
awk:Aho,Weinberger,Kernighan,報告生成器,格式化文本輸出
有多種版本:New awk(nawk),GNU awk(gawk)
gawk:模式掃描的處理語言
基本用法:
awk [options] 'program' var=value file...
awk [POSIX or GNU style options] -f programfile [--] file ...

基本格式:
awk [options] 'program' file...
program:pattern{action statements;...}
讀入文件一行,檢查是否符合pattern,是就執行action statments
BEGIN:沒有讀取文件前,先執行BEGIN
END:讀取完成文件後,執行END
省略action,則默認執行 print $0 的操作
在{}中,$1 $2要用,纔可以分割,用空格不行,可以用"\t"
分割符:
讀入行分割成$1 $2,默認是空格,不管幾個空格都壓縮成一個,-F設置分隔符
域:
行的所有字段$0爲所有域
記錄:
文件的每一行稱爲記錄,可以把多選,一行中的一部分作爲記錄,可以利用-v RS=“”來定義記錄分隔符

-F 列分隔符

-v 變量賦值,變量可以延伸到下一行
    FS=":" 列分隔符,FS=$PATH,可以引用shell中的變量 field space
        awk -v FS=$S '{pirnt $1,$3}' /etc/passwd
    OFS=":" 輸出時列分隔符
        awk -v OFS=*** '{print $1OSF$3}' /etc/passwd
    RS="" 輸入記錄分隔符,指定輸入時的換行符 record space
        awk -v RS="" ''
    ORS="" 輸出記錄分隔符,指定時不用在action中引用有有
        awk -v ORS=""
    自定義變量:
        awk -v var=123
        awk -F: '{title="hello"; print $1,title}' /etc/passwd

NF 字段數 number field
    awk -F: '{print NF}' /etc/passwd
    awk -F: '{print $NF}' /etc/passwd 最後一段
    awk -F: '{print $(NF-1)}' /etc/passwd 倒數第二段
NR 記錄數 number record
    awk -F: '{print NR,$1}' /etc/passwd 打印第一行的行號
FNR 各文件分別計數,記錄號
    awk '{print FNR}' /etc/fstab /etc/inittab
FILENAME 當前文件名
    awk '{print FILENAME}' /etc/fstab
ARGC 命令行參數的個數
    awk '{print ARGC}' /etc/fstab
ARGV 數組,保存的是命令行所給定的各參數
    awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab

-f awkScript

使用擴展正則表達式來定義-F後的分隔符
    df | grep "/dev/sd" | awk -F"[[:space:]]+|%" '{print $5}' (以多個連續空格或%爲分隔符)
    ![](https://s1.51cto.com/images/blog/201904/13/84d9d679c39c027aa452d3a4dea80eb1.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
    df | awk -F" +|%" '/^\/dev\/sd/{print $1,$5}'
    ![](https://s1.51cto.com/images/blog/201904/13/fde44b4f735edf5c63a437d4b247b1b9.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)

printf命令
printf "FORMAT",item1,item2,...
1、必須指定FORMAT
2、不會自動換行,需要顯示給出換行控制符,\n1
3、FORMAT中需要分別爲後面每個item指定格式符
格式符:與item一一對應
%c:顯示字符的ASCII碼
%d, %i:顯示十進制整數
%e, %E:顯示科學計數法數值
%f:%.2f,右對齊%10.2f,右對齊%-10.2f,顯示爲浮點數
%g, %G:以科學計數法或浮點形式顯示數值
%s:顯示字符串
%u:無符號整數
%%:顯示%自身
修飾符
#[.#] 第一個數字控制顯示的寬度;第二個#表示小數點後精度,%3.1f

  • 左對齊(默認右對齊) %-15s
  • 顯示數值的正負符號 %+d
    echo "100.123" | awk '{printf "The is a %d"kk,$0}'
    awk的操作符
    算術操作符:x+y x%y +x -x
    字符串操作符:沒有符號的操作符,字符串連接
    賦值操作符:= += -= *= /= %= ^= ++ --
    比較操作符:==, !=, >, >=, <, <=
    模式匹配符:~ !~
    awk -F: '$3 ~ /107/{print $1}' /etc/passwd 匹配第3列中等於107的行的用戶名
    awk從入門至放棄
    df | awk '$0 ~ "^/dev/sd" {print $0}' 打印匹配df命令以^/dev/sd開頭的行
    awk從入門至放棄
    邏輯操作符:與&&,或||,非!
    awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
    awk從入門至放棄
    awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
    awk從入門至放棄
    awk -F: ‘!($3==0) {print $1}' /etc/passwd
    awk從入門至放棄
    條件表達式(三目表達式)
    selector?if-true-expression:if-false-expression
    awk -F: '{$3>=1000?usertype="Common User":usertype=" SysUser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd
    awk從入門至放棄
    PATTERN:根據pattern條件,過濾匹配的行,再做處理
    (1)如果未指定:空模式,匹配每一行
    (2) /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來
    awk '/^UUID/{print $1}' /etc/fstab
    awk '!/^UUID/{print $1}' /etc/fstab
    (3) relational expression: 關係表達式,結果爲“真”纔會被處理
    只要是awk -F: '""{print $1,$3}' /etc/passwd中{print $1,$3}前""是空就是,只要有內容都是真
    字符串不空爲真,數值不爲0爲真
    真:結果爲非0值,非空字符串
    假:結果爲空字符串或0值
    (4) 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
    seq 10 | awk 'NR>2;NR<=5'
    打印全部行,且3 4 5 打印兩遍
    (5) BEGIN/END模式
    BEGIN{}:僅在開始處理文件中的文本之前執行一次
    END{}:僅在文本處理完成之後執行一次

    seq 10 | awk 'i=0' 這個awk是默認省略了{print $0}
    seq 10 | awk 'i=!i' 1、對空i取反爲非空,打印 2、對非空i取反,不打印,這樣循環,打印奇數行
    seq 10 | awk '!(i=!i)' 

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

    { 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

    if-else語句
    awk -F: '{if($3>=1000)print $1,$3}' /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}‘

    while語句
    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

    do-while語句
    awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'

    for循環語句
    語法:for(expr1;expr2;expr3) {statement;…}
    awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg

    switch語句
    語法:switch(expression) {case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2; ...; default: statementn}
    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}'

    awk '!line[$0]++' fl.txt 忽略重複行,第一次f1.txt的第一行爲line["123"]爲空,line["123"]++=line["123"]=1
    awk '!line[$0]++{pirint $0 line[$0]}' f1.txt 查看
    awk '{!line[$0]++; pirint $0 line[$0]}' f1.txt

    awk數組
    關聯數組:array[index-expression]
    index-expression
    (1)、可使用任意字符串,字符串要使用雙引號括起來
    (2)、如果某數組元素事先不存在,在引用時,awk會自動創建此元素,並將某值初始化爲"空串"
    (3)、若要判斷數組中是否存在某元素,要使用"index in array",格式進行遍歷
    若要遍歷數組中的每個元素,可使用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

    利用函數求男女的平均數
    name score gender
    a    100   m
    b    99    f
    c    80    f
    awk 'NR!=1{sum[$3]+=$2;num[$3]++}END{for(i in sum)print i,num[i];or(i in sum)print i,num[i];}'

    函數
    rand():返回0和1之間的一個隨機數
    srand()有種子才能造成隨機數
    awk 'BEGIN{srand();print rand()}'
    awk 'BEGIN{srand();print int(rand()*100)}'
    字符串處理:
    length([s]):返回指定字符串的長度
    sub(r,s,[t]):對t字符串搜索r表示模式匹配的內容,並將第一個匹配內容替換爲s
    echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'
    gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,並全部替換爲s所表示的內容
    split(s,array,[r]):以r爲分隔符,切割字符串s,並將切割後的結果保存至array所表示的數組中,第一個索引值爲1,第二個索引值爲2,…
    array[1]切割的第一列,array[2]切割後...
    ss -tn | awk '/^ESTAB{split($NF,ip,":");count[ip[1]]++};END{for(i in count)print i,count[i]}'
    自定義函數
    格式:
    function name ( parameter, parameter, ... ) {
    statements
    return expression
    }
    示例:
    cat fun.awk
    function max(x,y) {
    x>y?var=x:var=y
    return var
    }
    BEGIN{a=3;b=2;print max(a,b)}
    awk -f fun.awk
    調用shell中的命令
    awk 'BEGIN{system("hostname")}'
    awk 'BEGIN{score=100;system("echo your score is " score)}'

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