1. 程式人生 > >linux awk 命令筆記

linux awk 命令筆記

推薦awk學習系列
https://www.ibm.com/developerworks/cn/linux/shell/awk/awk-1/index.html
https://www.ibm.com/developerworks/cn/linux/shell/awk/awk-2/index.html
https://www.ibm.com/developerworks/cn/linux/shell/awk/awk-3/index.html
工具書
https://book.saubcy.com/AwkInAction/section_1/chapter_2_1.html

1 呼叫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)跟上面的是一樣的。

2 基本命令

2.1 行匹配語句 awk ” 只能用單引號

awk '{[pattern] action}'
{filenames}


test.sh檔案
將檔案按照’\t’或者’ ‘分割,輸出第一列和第四列的內容

#!/bin/bash
awk '{print $1,$4}'

執行

chmod +x test.sh
cat b | ./test.sh

結果 輸出b檔案中每行的第一列和第四列

2.2 指定分隔符關鍵字 -F

指令碼檔案

#!/bin/bash
awk -F, '{print $1,$4}'

指定分隔符為’,’

指定多個分隔符 -F ‘[]’
指令碼檔案

#!/bin/bash
awk -F '[\t,]' '{print $1}'

先按照’\t’切分,再按照’,’切分

2.3 設定變數

awk -v設定變數

指令碼檔案

#/bin/bash
awk -va=1 -vb=s '{print $1,$1+a,$1b}'

$1+a是計算第一列與變數a的和,如果$1為字串,則只返回變數a的數值,$1b是字串拼接,將$1與變數a的內容連結起來

2.4 篩選匹配

指令碼檔案

#/bin/bash
awk  '$1>3 && ($3 == "d" || $3 == "e") { print $0 }'

類c模式,左邊為條件,右邊為滿足條件的操作,這裡是滿足條件輸出當前行

2.5 正則

# 輸出第二列包含 "th",並列印第二列與第四列
$ awk '$2 ~ /th/ {print $2,$4}' log.txt
# 輸出包含"re" 的行
$ awk '/re/ ' log.txt
# 忽略大小寫
$ awk 'BEGIN{IGNORECASE=1} /this/' log.txt
# 模式取反
$ awk '$2 !~ /th/ {print $2,$4}' log.txt
$cat a
1.021 33
1#.ll   44
2.53 6
ss    7
awk 'BEGIN{total = 0;len = 0} {if($1~/^[0-9]+\.[0-9]*/){total += $1; len++}} END{print total/len}' a
$1~/^[0-9]+\.[0-9]*/表示$1與“/ /”裡面的正則表示式進行匹配,若匹配,則total加上$1,且len自增,即數目加1.“^[0-9]+\.[0-9]*”是個正則表示式,“^[0-9]”表示以數字開頭,“\.”是轉義的意思,表示“.”為小數點的意思。“[0-9]*”表示0個或多個數字

3 awk指令碼

關於awk指令碼,有兩個關鍵詞BEGIN和END。

  • 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
}

執行

awk -f cal.awd score

結果

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

4 其他

awk、sed、grep更適合的方向:

  • grep 更適合單純的查詢或匹配文字
  • sed 更適合編輯匹配到的文字
  • awk 更適合格式化文字,對文字進行較複雜格式處理

關於awk內建變數

  • 解釋一下變數:
  • 變數:分為內建變數和自定義變數;輸入分隔符FS和輸出分隔符OFS都屬於內建變數。
  • 內建變數就是awk預定義好的、內建在awk內部的變數,而自定義變數就是使用者定義的變數。

    FS:輸入欄位分隔符, 預設為空白字元
    OFS:輸出欄位分隔符, 預設為空白字元
    RS:輸入記錄分隔符(輸入換行符), 指定輸入時的換行符
    ORS:輸出記錄分隔符(輸出換行符),輸出時用指定符號代替換行符
    NF:當前行的欄位的個數(即當前行被分割成了幾列)
    NR:行號,當前處理的文字行的行號。
    FNR:各檔案分別計數的行號
    ARGC:命令列引數的個數
    ARGV:陣列,儲存的是命令列所給定的各引數
    自定義變數的方法
    方法一:-v varname=value ,變數名區分字元大小寫。

引用 http://www.runoob.com/linux/linux-comm-awk.html

5 筆記

  • 執行awk指令碼傳參
awk -f test.awk a="test" filename #入參a,資料型別為string
awk -f test.awk a=1 filename #入參a,資料型別為數字
# 在指令碼呢中直接用a訪問
  • awk指令碼中的陣列
#awk 遇到第一個賦值語句時,它將建立 myarray
myarray[1]="jim"
myarray[2]=456
#遍歷陣列
for ( x in myarray ) {
    print myarray[x]
}

注意:每次賦值以後都迴圈一次迴圈程式碼。雖然這是一個非常方便的 awk 功能,但它有一個缺點 – 當 awk 在陣列下標之間輪轉時,它不會依照任何特定的順序。
所以輸出可能是

jim
456

也可能是

456
jim

awk的性質: 陣列下標字串化
所以awk可以當作map來使用

myarr["name"]="Mr. Whipple"
print myarr["name"]

同樣的
可以判斷key是否在array中

if ( 1 in fooarray ) {
    print "Ayep!  It's there."
} else {
    print "Nope!  Can't find it."
}

刪除元素的操作

delete fooarray[1]