awk指令碼語言程式設計指南

東陸之滇發表於2019-01-21

AWK入門指南

安裝AWK

# 使用yum安裝
yum install gawk

# 安裝後檢查是否安裝ok
which awk
## 一般輸出安裝路徑是在: /bin/awk
複製程式碼

AWK 起步示例

假設存在一個檔案 emp.data,其中包含員工的姓名、薪資(美元/小時)以及小時數,一個員工一行資料,其內容如下:

Beth	4.00	0
Dan	3.75	0
kathy	4.00	10
Mark	5.00	20
Mary	5.50	22
Susie	4.25	18
複製程式碼

如果想列印出 工作時長超過0小時的員工姓名和工資(薪資乘以時間),以下命令可以完成:

awk '$3>0 {print $1, $2*$3}'  emp.data

複製程式碼

得到如下輸出:

kathy 40
Mark 100
Mary 121
Susie 76.5
複製程式碼

該命令告訴系統執行括號內的awk程式,從輸入檔案 emp.data 獲取所需要的資料。引號內的部分是個完整的awk程式,包含單個 模式-動作 語句。模式 $3>0 用於匹配第三列大於0的輸入行,動作: {print $1, $2*$3} 列印每個匹配行的第一個欄位、第二個欄位與第三個欄位的乘積。

還可以列印沒有工作過的員工姓名:

awk '$3==0 {print $1}'  emp.data
複製程式碼

將會輸出:

Beth
Dan
複製程式碼

AWK程式的結構

回過頭來看一下上述命令。引號之間的部分是awk程式語言寫就的程式。 每個awk程式都是 一個或多個 模式-動作 語句的序列:

pattern {pattern} pattern {pattern} ...

awk 的基本操作是一行一行的掃描輸入,搜尋匹配任意程式中模式的行。 詞語“匹配”的準確意義是視具體的模式而言,對於模式 $3>0 來說,意思是“條件為真”。 每個模式依次測試每個輸入行。對於匹配到行的模式,其對應的動作(也許包含多步)得到執行,然後讀取下一行並繼續匹配,直到所有的輸入讀取完畢。

模式 動作
$3==0 {print $1}

模式-動作 語句中的 模式或動作(但不是兩者同時省略)都可以省略。如果某個模式沒有動作,例如:

$3==0

那麼模式匹配到的每一行都會被打出來。輸出如下:

Beth    4.00    0
Dan     3.75    0
複製程式碼

如果是沒有動作的模式,例如: {print $1} 則會列印第一列,輸出如下:

Beth
Dan
kathy
Mark
Mary
Susie
複製程式碼

由於模式和動作兩者任一都是可選的,所以需要使用大括號包圍動作用以區分其他模式。

執行 awk 程式

執行awk程式有多種,可以輸入如下形式的命令列: awk 'program codes' inputfiles 從而在每個指定的輸入檔案上執行這個program。例如: awk '$3==0 {print $1}' file1 file2 列印 file1 和 file2 檔案中第三列為0的每一行的第一個欄位。

也可以省略命令列中的輸入檔案,僅僅輸入: awk 'program codes' 在這種情況下,awk 將會應用於你在終端接著輸入的任意資料行,直到你輸入一個檔案結束訊號(Unix系統上為control-d)。示例:

awk '$3>0 {print $1}'
Mary 20 1000   #輸入該行回車
Mary  # 計算機輸出,匹配到了資訊
Belly 30 3000  #繼續輸入改行
Belly #計算機輸出
複製程式碼

注意事項: 命令列中的程式是用單引號包圍著的。這會防止shell解釋程式中$這樣的字元,也允許程式的長度超過一行。 當程式比較長的時候,可以將程式寫入到一個檔案,以下命令列: awk -f programfile optional list of input files

其中 -f 選項指示 awk 從指定檔案中獲取程式。可以使用任意檔名替換 programfile。

awk 的錯誤提示

如果你的 awk 程式存在錯誤, awk 會給你一些診斷資訊。例如,如果你打錯了大括號,如下所示:

awk '$3==0 [print $1}' emp.data 會提示如下錯誤:

awk: $3==0 [print $1}
awk:       ^ syntax error
awk: $3==0 [print $1}
awk:                ^ syntax error
複製程式碼

簡單輸出

awk中僅僅只有兩種型別 數值字元 構成的字串。通常情況下,一個欄位是一個不包含任何空格或製表符的連續字元序列。 當前輸入的 行中的第一個欄位被稱作 $1,第二個是 $2,以此類推。 整個行的內容被定義為 $0。 每一行的欄位數量可以不同。

大都數情況下,我們僅僅只是列印出其中每一行的某些欄位,或者也還需要做一些計算。

列印每一行

如果一個動作沒有任何模式,這個動作針對所有輸入的行進行操作。 print 語句用來列印(輸出)當前輸入的行。 所以 {print} 等效於 {print $0}

列印特定行

{print $1,$3} 將輸出:

Beth 0
Dan 0
kathy 10
Mark 20
Mary 22
Susie 18
複製程式碼

在 print 語句中被逗號分隔的表示式,在預設情況下他們將會用一個空格分割來輸出。 每一行print生成的內容都會以一個換行符作為結束。但這些預設行為都可以自定義。

NF,欄位數量

AWK 會對當前輸入的行有多少欄位進行計數,並且將當前行的欄位數量儲存在一個內建的稱為 NF 的變數中。因此 {print NF,$1,$NF} 會列印出 每一行的欄位數量、第一個欄位的值、最後一個欄位的值。 輸出:

3 Beth 0
3 Dan 0
3 kathy 10
3 Mark 20
3 Mary 22
3 Susie 18
複製程式碼

列印行號

awk 提供了另一個內建變數, NR。他儲存了當前已經讀取了多少行的計數。可以使用 NR和$0給emp.data的每一行加上行號: {print NR,$0} 輸出如下:

1 Beth  4.00    0
2 Dan   3.75    0
3 kathy 4.00    10
4 Mark  5.00    20
5 Mary  5.50    22
6 Susie 4.25    18
複製程式碼

在輸出中新增內容

還可以在欄位中間或者計算的值中間列印輸出想要的內容: {print "total pay for", $1, "is", $2*$3} 輸出如下:

total pay for Beth is 0
total pay for Dan is 0
total pay for kathy is 40
total pay for Mark is 100
total pay for Mary is 121
total pay for Susie is 76.5
複製程式碼

高階輸出

print 語句可用於快速而簡單的輸出。若要嚴格按照你所想的格式化輸出,則需要使用 printf 語句。

欄位排隊

printf 語句格式如下:

printf(format, value1, value2, ..., valueN)

其中 format 是字串,包含要逐字列印的文字,穿插在 format 之後的每個值該如何列印的規格。一個規格是一個 % 符,後面跟著一些字元,用來控制一個 value 的格式。因此,有過少個 value 要列印,在 fromat 中就要有多少個 % 規格。 列印每個員工的總薪酬: {printf("total pay for %s is $%.2f\n", $1, $2*$3)} 輸出如下:

awk '{printf("total pay for %s is $%.2f\n", $1, $2*$3)}'  emp.data
total pay for Beth is $0.00
total pay for Dan is $0.00
total pay for kathy is $40.00
total pay for Mark is $100.00
total pay for Mary is $121.00
total pay for Susie is $76.50
複製程式碼

排序輸出

以薪酬遞增的方式輸出每一行:

awk '{printf("%6.2f %s\n", $2*$3, $0)}' emp.data | sort

將awk的輸出通過管道傳給 **sort **命令,輸出如下:

  0.00  Beth    4.00    0
  0.00  Dan     3.75    0
100.00  Mark    5.00    20
121.00  Mary    5.50    22
 40.00  kathy   4.00    10
 76.50  Susie   4.25    18
複製程式碼

選擇

awk 的模式適用於為進一步的處理從輸入中選擇相關的資料行。由於不帶動作的模式會列印所有匹配的行,所以很多awk程式僅僅包含一個模式。本節將給出一些有用的模式示例。

通過對比選擇

使用一個對比模式來選擇每小時賺5美元或更多的員工記錄,亦即第二個欄位大於等於5的行: $2>=5

awk '$2>=5'  emp.data
Mark    5.00    20
Mary    5.50    22
複製程式碼

通過計算選擇

awk '$2*$3>50 {printf("$%.2f for %s\n", $2*$3, $1)}'  emp.data
$100.00 for Mark
$121.00 for Mary
$76.50 for Susie
複製程式碼

通過文字內容選擇

除了數值測試,還可以選擇包含特定單詞或短語的輸入行。這個程式會列印所有第一個欄位為 Susie 的行:

$1=="Susie"

操作符 == 用於測試相等性。 也可以使用正規表示式的模式查詢包含任意任意字母組合,單詞或短語的文字。如以下可以匹配到任意位置包含Susie的行: /Susie/

awk '/Susie/'  emp.data
Susie   4.25    18
複製程式碼

模式組合

可以使用括號和邏輯操作符號與&&、或||,以及 非! 對模式進行組合。 $2>=4||$3>=20 會列印第二個欄位大於等於4或者第三個欄位大於等於20的行:

awk '$2>=4||$3>=20'  emp.data
Beth    4.00    0
kathy   4.00    10
Mark    5.00    20
Mary    5.50    22
Susie   4.25    18
複製程式碼

BEGIN 與 END

特殊模式 BEGIN 用於匹配第一個輸入檔案的第一行之前的位置。END 則用於匹配處理過的最後一個檔案的最後一行的位置。

這個程式使用 BEGIN 來輸出一個標題:

BEGIN {print "Name RATE HOURS"; print ""}
    {print}
複製程式碼
awk 'BEGIN {print "Name RATE HOURS"; print ""}
{print}' emp.data

## 輸出如下:

Name RATE HOURS

Beth    4.00    0
Dan     3.75    0
kathy   4.00    10
Mark    5.00    20
Mary    5.50    22
Susie   4.25    18
複製程式碼

注意事項:

  • awk 可以在一行上放多個語句,步過要使用分號;進行分隔。

  • 普通的 print 是列印當前輸入行, print "" 則會列印一個空行。

AWK 工作流圖

Awk 工作流圖

AWK 是按一行一行地讀取輸入的。

  • 1.首先執行 BEGIN
  • 2.從輸入中讀取一行
  • 3.在這次讀取的這一行中執行 AWK 命令
  • 4.如果檔案還沒有讀取完畢,則重複步驟2、3
  • 5.執行 END 塊中的 awk 命令

使用 AWK 進行計算

一個動作就是一個以新行或者分號分隔的語句序列。

計數
$3 > 15 {emp = emp + 1}
END {print emp, "employees worked more than 15 hours"}
複製程式碼
awk '$3 > 15 {emp = emp + 1}
> END {print emp, "employees worked more than 15 hours"}' emp.data

## 輸出結果:
3 employees worked more than 15 hours
複製程式碼

用作數字的 awk 變數的預設初始值為0, 所以不需要初始化 emp。建立一個變數emp初始值為0,如果讀入的那一行的第三個欄位大於15,則emp在自身值的基礎上自增1,讀完最後一行後輸出存在多少個員工工作時長超過15個小時的語句。

求和與平均值

為計算員工數目,可以使用內建變數 NR,儲存了當前位置讀取的行數;在所有輸入的結尾它的值就是所讀行的總行數。

END {print NR, "employees"}

awk 'END {print NR, "employees"}'  emp.data

## 輸出結果為:
6 employees
複製程式碼

如下是一個使用 NR 來計算薪酬均值的程式:

awk '{pay = pay + $2*$3}
> END {print NR, "employees"
> print "total pay is", pay
> print "average pay is", pay/NR
> }' emp.data

## 輸出結果為:
6 employees
total pay is 337.5
average pay is 56.25
複製程式碼

處理文字

awk 的優勢之一是能像大多數語言處理數字一樣方便地處理字串。 awk 可以儲存數字也可以儲存字元。找出時薪最高的員工:

$2 > maxrate { maxrate = $2; maxemp = $1 }
END { print "highest hourly rate:", maxrate, "for", maxemp }
複製程式碼
 awk '$2 > maxrate { maxrate = $2; maxemp = $1 }
> END { print "highest hourly rate:", maxrate, "for", maxemp }' emp.data

## 輸出結果為:
highest hourly rate: 5.50 for Mary
複製程式碼
awk '{names = names $1 " "}                    
END {print names}' emp.data

## 輸出結果:
Beth Dan kathy Mark Mary Susie 
複製程式碼

列印最後一個輸入行

雖然在 END 動作中 NR 還保留著它的值, 但 $0 沒有。

{last = $0}
END {print last}
複製程式碼
awk '
> {last = $0}
> END {print last}' emp.data

## 輸出結果:
Susie   4.25    18
複製程式碼

AWK 內建函式

前面已經看到 awk 內建變數用來儲存某些頻繁使用的數量, NF 表示所在行的總列數, NR 表示當前是第多少行... 還有內建函式用來計算其他有用的數值。除了 平方根、對數、隨機數此類的算術函式外,還有操作文字的函式。其中之一是 length 用於計算一個字串的長度。

awk '{print $1, length($1)}'  emp.data

## 輸出結果:
Beth 4
Dan 3
kathy 5
Mark 4
Mary 4
Susie 5
複製程式碼

行、單詞以及字元的計數

使用 length、NF、NR來統計輸入中行、單詞以及字元的數量。為了簡便,將每個欄位看作一個單詞。

awk ' { nc = nc + length($0) + 1
>       nw = nw + NF
>     }
> END { print NR, "lines,", nw, "words,", nc, "characters" }' emp.data

## 輸出結果為:
6 lines, 18 words, 82 characters
複製程式碼

因為 $0 不會包含行末的換行符,所以另外加了個1。

AWK 控制語句

awk 為選擇提供了一個 if-else 語句, 以及為迴圈提供了幾個語句,它們僅在動作中使用。

if-else 語句

如下是一個計算時薪超過6美元的員工總薪酬與平均薪酬。它使用一個 if 來防範零除問題。

$2 > 6 { n = n+1; pay = pay + $2*$3 }
END {
    if(n > 0)
        print n, "employees, total pay is", pay,
               "average pay is", pay/n
    else
        print "no employees are paid more than $6/hour"
        
}

複製程式碼
awk '$2 > 6 { n = n+1; pay = pay + $2*$3 }
> END {
>     if(n > 0)
>         print n, "employees, total pay is", pay,
>                "average pay is", pay/n
>     else
>         print "no employees are paid more than $6/hour"
>         
> }' emp.data

## 輸出結果為:
no employees are paid more than $6/hour
複製程式碼

注意事項: 我們可以使用一個逗號將一個長語句截斷為多行來書寫.

while 語句
{
    i = 1
    while ( i <=3 ){
        # while 迴圈體(這一行是註釋內容)
        printf("\t%.2f\n", $1*(1+$2)^i)
        i = i + 1
    }
}
複製程式碼

while 後面是圓括號,裡面是布林表示式。 迴圈體是條件後大括號包圍的語句。 ^ 是指數操作符。 # 後面是註釋。

演示1000美元,利率為6%與12%,5年的複利分別是如何增長的:

awk '
> {
>     i = 1
>     while ( i <=5 ){
>         # while 迴圈體(這一行是註釋內容)
>         printf("\t%.2f\n", $1*(1+$2)^i)
>         i = i + 1
>     }
> }
> ' 
1000 .06 5
        1060.00
        1123.60
        1191.02
        1262.48
        1338.23
1000 .12 5
        1120.00
        1254.40
        1404.93
        1573.52
        1762.34
複製程式碼
for 語句

使用for迴圈實現上述例子:

awk '
> {
>     for( i = 1; i <= $3; i = i+1 ){
>         printf("\t%.2f\n", $1*(1+$2)^i)
>     }
> }
> '
1000 .06 5
        1060.00
        1123.60
        1191.02
        1262.48
        1338.23
1000 .12 5
        1120.00
        1254.40
        1404.93
        1573.52
        1762.34
複製程式碼

陣列

awk 為儲存一組相關的值提供了陣列,雖然陣列給予了awk很強的能力,但是在這裡我們僅僅展示一個簡單的例子。 第一個動作將輸入行存為陣列 line 的連續元素; 第一行放在line[1],第二行放在line[2]。 END 動作使用一個while語句從後往前列印陣列中的輸入行:

# 反轉-按行逆序列印輸入

{line[NR] = $0}

END {
        i = NR
        while(i > 0){
            print line[i]
            i = i-1
        }
}

複製程式碼
awk '
> {line[NR] = $0}
> 
> END {
>         i = NR
>         while(i > 0){
>             print line[i]
>             i = i-1
>         }
> }' emp.data

# 輸出結果為:
Susie   4.25    18
Mary    5.50    22
Mark    5.00    20
kathy   4.00    10
Dan     3.75    0
Beth    4.00    0
複製程式碼

--dump-variables 操作檢視全域性變數

-dump-variables[=file] 操作可以列印全域性變數到檔案中,預設是“awkvars.out”檔案。

awk --dump-variables ''

# 檢視檔案awkvars.out 
cat awkvars.out 

ARGC: number (1)
ARGIND: number (0)
ARGV: array, 1 elements
BINMODE: number (0)
CONVFMT: string ("%.6g")
ERRNO: number (0)
FIELDWIDTHS: string ("")
FILENAME: string ("")
FNR: number (0)
FS: string (" ")
IGNORECASE: number (0)
LINT: number (0)
NF: number (0)
NR: number (0)
OFMT: string ("%.6g")
OFS: string (" ")
ORS: string ("\n")
RLENGTH: number (0)
RS: string ("\n")
RSTART: number (0)
RT: string ("")
SUBSEP: string ("\034")
TEXTDOMAIN: string ("messages")

複製程式碼

--help 操作可以尋得幫助

awk --help
# 輸出資訊如下:

Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:          GNU long options:
        -f progfile             --file=progfile
        -F fs                   --field-separator=fs
        -v var=val              --assign=var=val
        -m[fr] val
        -O                      --optimize
        -W compat               --compat
        -W copyleft             --copyleft
        -W copyright            --copyright
        -W dump-variables[=file]        --dump-variables[=file]
        -W exec=file            --exec=file
        -W gen-po               --gen-po
        -W help                 --help
        -W lint[=fatal]         --lint[=fatal]
        -W lint-old             --lint-old
        -W non-decimal-data     --non-decimal-data
        -W profile[=file]       --profile[=file]
        -W posix                --posix
        -W re-interval          --re-interval
        -W source=program-text  --source=program-text
        -W traditional          --traditional
        -W usage                --usage
        -W use-lc-numeric       --use-lc-numeric
        -W version              --version

To report bugs, see node `Bugs' in `gawk.info', which is
section `Reporting Problems and Bugs' in the printed version.

gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.

Examples:
        gawk '{ sum += $1 }; END { print sum }' file
        gawk -F: '{ print $1 }' /etc/passwd
複製程式碼

--version 檢視版本資訊

awk --version
# 輸出結果如下:

GNU Awk 3.1.7
Copyright (C) 1989, 1991-2009 Free Software Foundation.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
複製程式碼

-v 操作

-v 操作允許給一個變數分配值。允許在程式執行之前分配。

awk -v name=LFF 'BEGIN {printf("username=%s\n", name)}'

# 輸出結果為:
username=LFF
複製程式碼

--lint 操作提示資訊

--lint 操作允許輸出檢查資訊,比如當引數提供錯誤,會將警告資訊當作錯誤。

awk --lint '' /bin/ls

# 輸出結果為:
awk: warning: empty program text on command line
awk: warning: source file does not end in newline
awk: warning: no program text at all!
複製程式碼

正則匹配

匹配輸入行中包含字元a的行,全部輸出。

awk '/a/ {print $0}'  emp.data

# 輸出結果為:
Dan     3.75    0
kathy   4.00    10
Mark    5.00    20
Mary    5.50    22
複製程式碼

列印輸入行中包含字元a的行數:

awk '/a/ {++cnt} END {print "匹配的行數為:", cnt}' emp.data

# 輸出結果為:
匹配的行數為: 4
複製程式碼

內建變數

ARGC :命令列中提供的引數個數

shell awk 'BEGIN {print "Arguments =", ARGC}' One Two Three Four Arguments = 5

ARGV 表示命令列入參構成的陣列,索引是 0~ARGC-1
 awk 'BEGIN { 
>    for (i = 0; i < ARGC - 1; ++i) { 
>       printf "ARGV[%d] = %s\n", i, ARGV[i] 
>    } 
> }' one two three four

# 輸出結果為:
ARGV[0] = awk
ARGV[1] = one
ARGV[2] = two
ARGV[3] = three
複製程式碼
CONVFMT

表示數字的轉換格式。預設值是 %.6g

awk 'BEGIN { print "Conversion Format =", CONVFMT }'

#輸出:
Conversion Format = %.6g
複製程式碼
ENVIRON 環境變數
awk 'BEGIN { print ENVIRON["USER"] }'

# 輸出當前使用者
deploy
複製程式碼

我們可以藉助env命令檢視linux伺服器上的全部環境變數:

env

# 檢視當前伺服器上的所有環境變數
HOSTNAME=sz-local3
TERM=vt100
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=10.89.4.224 53217 22
QTDIR=/usr/lib64/qt-3.3
OLDPWD=/data/app
QTINC=/usr/lib64/qt-3.3/include
SSH_TTY=/dev/pts/0
GREP_OPTTIONS=--color=always
USER=deploy
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/deploy
PATH=/usr/lib/jdk1.7.0_76/bin:/usr/lib64/qt-3.3/bin:/data/app/node-v4.2.4-linux-x64/bin:/usr/lib/jdk1.7.0_76/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/deploy/bin
PWD=/data/app/lff
JAVA_HOME=/usr/lib/jdk1.7.0_76
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/home/deploy
LOGNAME=deploy
QTLIB=/usr/lib64/qt-3.3/lib
CVS_RSH=ssh
CLASSPATH=/usr/lib/jdk1.7.0_76/lib:/usr/lib/jdk1.7.0_76/lib:
SSH_CONNECTION=10.89.4.224 53217 10.193.1.27 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
複製程式碼
FILENAME 表示當前檔案
awk 'END {print FILENAME}' emp.data

# 輸出結果為:
emp.data
複製程式碼
FS 表示檔案分隔符

FS 表示檔案分割符,預設是空白字元。也可以使用 -F 命令列變更。

awk 'BEGIN {print "FS = " FS}' | cat -vte

# 輸出結果為:
FS =  $
複製程式碼
NF 表示當前行的欄位(列數)
NR 表示當前讀到的行數
RLENGTH

表示匹配函式 match 到的字串的長度。

awk '
BEGIN {
       if(match("One Two Three", "re")){
          print RLENGTH
       }
}'

# 匹配到了Three中的re,輸出結果為:
2
複製程式碼
RSTART 表示第一個match函式匹配到的字串中的位置
awk '
BEGIN {
       if(match("One Two Three There", "re")){
          print RSTART 
       }
}'

# 從O開始,到Three的r,位置處於11,輸出結果為:
11
複製程式碼
$0 表示全部的輸入記錄
$n 表示第n列(第n個欄位),以檔案分隔符分隔,預設是空白字元。
ARGIND 表示當前處理的 ARGV 的索引值
PROCINFO 表示程式相關資訊
awk 'BEGIN {print PROCINFO["pid"]}'
5142
複製程式碼

運算子操作

自增符操作
awk 'BEGIN {print ++a}'
# 先自增,輸出結果為:
1
# 後自增,輸出結果為:
awk 'BEGIN {print a++}'
0
複製程式碼
自減符操作
awk 'BEGIN {print --a}'
-1
awk 'BEGIN {print a--}'
0
複製程式碼
+=、 -=、 *=、/=、%=、 ^=、**=操作
awk 'BEGIN {print cnt+=10; print cnt}'
10
10

awk 'BEGIN {cnt=10 ;print cnt*=10; print cnt}'
100
100

awk 'BEGIN {cnt=10 ;print cnt-=10; print cnt}'
0
0
awk 'BEGIN {cnt=10 ;print cnt/=10; print cnt}'
1
1
awk 'BEGIN {cnt=10 ;print cnt%=10; print cnt}'
0
0
awk 'BEGIN {cnt=10 ;print cnt^=10; print cnt}'
10000000000
10000000000
awk 'BEGIN {cnt=10 ;print cnt**=10; print cnt}'
10000000000
10000000000
複製程式碼
關係運算子
  • ==
  • !=
  • <
  • <=
  • >
  • >=
邏輯運算子
  • &&
  • ||
  • !
三目運算子
  • ? :
字串連線符

空白字元是字串連線符

awk 'BEGIN {a="hello, "; b="world!"; c= a b; print(c)}'

# 輸出連線結果
hello, world!
複製程式碼
陣列關係操作符

for in 操作常用於遍歷陣列。

awk '
> BEGIN { arr[1] = "a"; arr[2] = "b"; arr[3] = "c";  
> for(i in arr){
>     print("a[", i, "]=", arr[i])
> }
> }'

# 遍歷輸出陣列元素:
a[ 1 ]= a
a[ 2 ]= b
a[ 3 ]= c

複製程式碼
正規表示式操作符
  • 點符**.** : 匹配任意單個字元

示例:

echo -e "cat\nbat\nfun\nfin\nfan" | awk '/f.n/'

fun
fin
fan
複製程式碼
  • **^**符:匹配開頭

匹配 The 開頭的字串:

echo -e "This\nThat\nThere\nTheir\nthese" | awk '/^The/'

There
Their
複製程式碼
  • **$**符:匹配結尾

匹配 n 結尾的字串:

echo -e "knife\nknow\nfun\nfin\nfan\nnine" | awk '/n$/'

fun
fin
fan
複製程式碼
  • [] 符 :匹配字符集多選一

匹配 Call 或者 Tall:

echo -e "Call\nTall\nBall" | awk '/[CT]all/'
 
Call
Tall
複製程式碼
  • 排除匹配

使用^排除,匹配不是 Call且不是Tall的字串:

echo -e "Call\nTall\nBall" | awk '/[^CT]all/'

Ball
複製程式碼
  • 可選匹配

匹配 Call 或者 Tall

echo -e "Call\nTall\nBall\nSmall\nShall" | awk '/Call|Ball/'

Call
Ball
複製程式碼
  • 符號 :0 或 1次匹配
echo -e "Colour\nColor" | awk '/Colou?r/'

Colour
Color
複製程式碼
  • * 符號: 表示0或多個匹配
echo -e "ca\ncat\ncatt" | awk '/cat*/'

ca
cat
catt
複製程式碼
  • () 分組匹配
echo -e "Apple Juice\nApple Pie\nApple Tart\nApple Cake" | awk 
   '/Apple (Juice|Cake)/'
   
Apple Juice
Apple Cake
複製程式碼

陣列

awk 'BEGIN {
   fruits["mango"] = "yellow";
   fruits["orange"] = "orange"
   print fruits["orange"] "\n" fruits["mango"]
}'

orange
yellow
複製程式碼
delete 刪除陣列元素
awk 'BEGIN {
   fruits["mango"] = "yellow";
   fruits["orange"] = "orange";
   delete fruits["orange"];
   for(i in fruits){print fruits[i]}
}'

# 刪除orange後,只剩下yello
yellow

複製程式碼
多維陣列
100   200   300
400   500   600
700   800   900
複製程式碼

array[0][0] 儲存 100,array[0][1] 儲存 200。 正確的語法是 array["0,0"] = 100

awk 'BEGIN {
   array["0,0"] = 100;
   array["0,1"] = 200;
   array["0,2"] = 300;
   array["1,0"] = 400;
   array["1,1"] = 500;
   array["1,2"] = 600;

   # print array elements
   print "array[0,0] = " array["0,0"];
   print "array[0,1] = " array["0,1"];
   print "array[0,2] = " array["0,2"];
   print "array[1,0] = " array["1,0"];
   print "array[1,1] = " array["1,1"];
   print "array[1,2] = " array["1,2"];
}'
複製程式碼

字串函式

index(str, substr)

子串 substr 出現在字串 str 中的開始位置,從1開始計數。

awk 'BEGIN {print index("Hello", "ll")}'
3
複製程式碼
gsub(regex, sub, string)

正則匹配 regex,將其替換為 sub指定的內容, string是所選的字串。

awk 'BEGIN { str = "Hello,World!"; gsub("World", "Lily", str); print str}'
Hello,Lily!
複製程式碼
match(str, regex)

匹配則返回regex在str中的起始位置,否則返回0表示沒有匹配到。

awk 'BEGIN {str = "Hello,world!"; ret = match(str, "wo"); print str, ret}'
Hello,world! 7
複製程式碼
split(str, arr, regex)

將 str 按 regex 匹配拆分,得到的每個拆分作為元素儲存在 arr 陣列中。

awk 'BEGIN {str = "Hello,Hellokitty"; split(str, arr, ",");  
for(ele in arr){
    print arr[ele]
}}'

Hello
Hellokitty
複製程式碼
strtonum(str)

將字串強轉成數值型別, str開頭是0的話會轉為八進位制, 是0x或0X開頭的話會轉為十六進位制。

 awk 'BEGIN {
>    print "Decimal num = " strtonum("123")
>    print "Octal num = " strtonum("0123")
>    print "Hexadecimal num = " strtonum("0x123")
> }'
Decimal num = 123
Octal num = 83
Hexadecimal num = 291
複製程式碼
substr(str, start, l)

獲取字串,從字串 str 中的 start位置開始擷取長度為 L 的字串。

awk 'BEGIN {str = "nihaoya!"; print substr(str, 1, 2)}'
ni
複製程式碼
tolower(str)

將字串 str 小寫化。

awk 'BEGIN{ print tolower("HeLLo")}'
hello
複製程式碼
toupper(str)

將字串 str 大寫化。

awk 'BEGIN{ print toupper("HeLLo")}'
HELLO
複製程式碼

時間函式

systime()

獲取自 1970-01-01 00:00:00 至今的unix時間戳

awk 'BEGIN {print systime()}'
1545742584
複製程式碼
mktime(datespec)

將指定的日期格式串轉換為時間戳,datespec 格式是 YYYY mm dd HH MM SS

awk 'BEGIN {print mktime("2018 12 25 21 07 00")}'
1545743220
複製程式碼
strftime(format, timestamp)

將時間戳 timestamp 轉換成指定格式format的字串

 awk 'BEGIN {
>    print strftime("Time = %m/%d/%Y %H:%M:%S", systime())
> }'
Time = 12/25/2018 21:11:09
複製程式碼

位操作函式

and

按位與

awk 'BEGIN {
   num1 = 10
   num2 = 6
   printf "(%d AND %d) = %d\n", num1, num2, and(num1, num2)
}'

# 輸出結果為:
(10 AND 6) = 2
複製程式碼
lshift(num, size)

將num按位左移size位數, 左移一位相當於乘以2

awk 'BEGIN {print lshift(10, 1)}'
20
複製程式碼
rshift(num, size)

將num按位右移size位數, 右移一位相當於除以2

awk 'BEGIN {print rshift(10, 1)}'
5
複製程式碼
or 按位或
awk 'BEGIN {
   num1 = 10
   num2 = 6
   printf "(%d OR %d) = %d\n", num1, num2, or(num1, num2)
}'

# 輸出結果為:
(10 OR 6) = 14
複製程式碼
xor 異或
awk 'BEGIN {
   num1 = 10
   num2 = 6
   printf "(%d XOR %d) = %d\n", num1, num2, xor(num1, num2)
}'

# 輸出結果為:
(10 XOR 6) = 12
複製程式碼

自定義函式

語法形式:

function function_name(argument1, argument2, ...) { 
   function body
}
複製程式碼

示例:

# Returns minimum number
function find_min(num1, num2){
   if (num1 < num2)
   return num1
   return num2
}
# Returns maximum number
function find_max(num1, num2){
   if (num1 > num2)
   return num1
   return num2
}
# Main function
function main(num1, num2){
   # Find minimum number
   result = find_min(10, 20)
   print "Minimum =", result
  
   # Find maximum number
   result = find_max(10, 20)
   print "Maximum =", result
}
# Script execution starts here
BEGIN {
   main(10, 20)
}
複製程式碼

輸出轉移操作

重定向資料到檔案

我們還可以將資料匯入到檔案中。在 print 或者 printf 後增加重定向的檔案語句。 語法:

print data > outputfile

將資料 data 寫入到 outputfile,如果 outputfile 不存在則建立。當指定重定向時,檔案 output 會清除所有內容,然後寫入資料。順序寫操作則不會提前清除檔案內容,只是追加。

#"Old data" 寫入 message.txt 檔案中,沒有則建立 message.txt 檔案。
echo "Old data" > message.txt
# 檢視檔案內容
cat message.txt 
# 輸出結果:
Old data
複製程式碼

然後執行:

awk 'BEGIN {print "Hello,World!" > "message.txt"}'
cat message.txt 
# 檔案的舊內容清楚了,內容已經被替換
Hello,World!
複製程式碼
追加內容到檔案中

print DATA >> output-file

echo "Old data" > /tmp/message.txt
cat /tmp/message.txt
# 檢視檔案內容
Old data

# 追加內容到檔案中
awk 'BEGIN { print "Hello, World !!!" >> "/tmp/message.txt" }'
cat /tmp/message.txt

#  輸出內容:
Old data
Hello, World !!!
複製程式碼
管道 pipe

可能需要傳送輸出資料到其它程式,通過管道而不是檔案。 這種轉移方式會開啟一個管道命令,並且會通過管道將資料項通過管道傳到另一個程式去執行命令。 轉移引數是一個 awk 表示式。

管道的語法如下:

print items | command

示例:使用 tr 命令將小寫轉換為大寫

awk 'BEGIN { print "hello, world !!!" | "tr [a-z] [A-Z]" }'
HELLO, WORLD !!!
複製程式碼

更過關於 tr 的使用方法,可以使用 tr --help 檢視幫助資訊。

雙向通訊

awk 可以通過 |& 跟外部程式通訊。

awk 'BEGIN {
>    cmd = "tr [a-z] [A-Z]"
>    print "hello, world !!!" |& cmd
>    close(cmd, "to")
>    
>    cmd |& getline out
>    print out;
>    close(cmd);
> }'
HELLO, WORLD !!!
複製程式碼

說明:

  • 第一條語句,cmd="tr [a-z] [A-Z]" ,是我們建立雙向通訊的命令。
  • 接下來的語句,print 命令提供輸入到 tr 命令。 這裡的 |& 表示雙向通訊。
  • 第三條語句,close(cmd,"to") ,在完成執行後,關閉 to 程式。
  • cmd |& getline out 藉助getline函式將結果輸出 到 out 變數中。
  • 最後列印out,並使用close函式關閉命令。

整齊列印

awk 'BEGIN { printf "Hello\nWorld\n" }'

# 輸出結果為:
Hello
World
複製程式碼
水平tab間隔列印
awk 'BEGIN { printf "Sr No\tName\tSub\tMarks\n" }'

Sr No   Name    Sub Marks
複製程式碼
垂直tab列印
awk 'BEGIN { printf "Sr No\vName\vSub\vMarks\n" }'

# 輸出結果為:
Sr No
     Name
         Sub
            Marks

複製程式碼
回車列印
awk 'BEGIN { printf "Field 1\rField 2\rField 3\rField 4\n" }'

輸出:
Field 4
複製程式碼
換頁列印
awk 'BEGIN { printf "Sr No\fName\fSub\fMarks\n" }'
Sr No
     Name
         Sub
            Marks
複製程式碼
格式說明符
  • %c : 表示一個單個字元
awk 'BEGIN { printf "ASCII value 65 = character %c\n", 65 }'
ASCII value 65 = character A
複製程式碼
  • %d and %i : 表示十進位制的整數
awk 'BEGIN { printf "Percentags = %d\n", 80.66 }'

輸出結果為:
Percentags = 80
複製程式碼
  • %e and %E : 科學記數法
awk 'BEGIN { printf "Percentags = %E\n", 80.66 }'

輸出結果為:
Percentags = 8.066000e+01
複製程式碼
  • %f : 浮點數
awk 'BEGIN { printf "Percentags = %f\n", 80.66 }'

輸出結果為:
Percentags = 80.660000
複製程式碼
  • %s : 表示字串
awk 'BEGIN { printf "Name = %s\n", "Sherlock Holmes" }'

輸出結果為:

Name = Sherlock Holmes
複製程式碼
  • %nd : 指定寬度列印

awk 'BEGIN { 
   num1 = 10; num2 = 20; printf "Num1 = %10d\nNum2 = %10d\n", num1, num2 
}'

# 輸出結果為:
Num1 =         10
Num2 =         20
複製程式碼

AWK 概覽

AWK 是一種解釋性程式語言。是專門為處理文字而設計的。名字是來自於設計者的名字 —— Alfred Aho, Peter Weinberger, and Brian Kernighan.

AWK 的型別

  • AWK : AT&T 實驗室
  • NAWK :AWK 的新的改進版本
  • GAWK : GNU AWK。 所有GNU/Linux發行版都是GAWK。它與AWK和NAWK完全相容。

AWK 的典型應用場景

  • 文字處理
  • 生成格式化的文字報告
  • 處理算術操作
  • 處理字串操作

AWK 環境

描述如何在 GNU/Linux 系統中安裝 AWK 環境。

安裝包管理器

一般情況下, AWK 預設在大都數 GNU/Linux 系統中都是安裝發行的。 你可以使用 which 命令,檢查awk在系統中是否安裝好了。 如果沒有安裝 awk, 可以按如下命令藉助 高階安裝包 APT安裝 AWK:

sudo apt-get update
sudo apt-get install gawk
複製程式碼
yum install gawk

# 檢視
which awk

# 輸出結果為:
/bin/awk
複製程式碼

從原始碼中安裝:

相關文章