linux工具-awk
目錄
1. 基本知識
1.1. 名稱由來
awk是其設計者名字首字母.
1.2. 語法格式
awk [options] 'pattern {action}' filename
1.3. 執行流程
對如下語句:
awk 'BEGIN {action1} pattern {action2} END {action3}' filename
執行流程如下:
- 執行BEGIN {action1}語種塊中的語句.
- 從檔案或STDIN逐行讀取, 對每一行執行pattern {action2}, 直到全部讀取完成.
- 執行END {action3}語種塊中的語句.
例子: 列印每一行, 並且在開頭和結尾分別列印Start和END.print語句不帶引數時就列印整行內容
例子:對第2列進行累加, 在BEGIN中為i賦初值, 在END中列印i(累加結果).
$ echo -e "a 1 a\na 2 a\na 3 a" | \
> awk 'BEGIN {i=0} {i+=$2} END {print i}'
6
1.4. 術語解釋
術語 | 說明 |
---|---|
記錄 | awk把每一個以換行符結束的行稱為一個記錄, NR即記錄的個數 |
域 | 記錄中每個單詞稱做"域", 預設以空格或Tab分隔, NF即域的個數. |
2. options
選項 | 說明 |
---|---|
-v | 引數傳遞 |
-f | 指定指令碼檔案 |
-F | 指定分隔符 |
-V | 檢視awk版本號 |
例子1:指定列分隔符
檔案內容
$ cat demo.txt root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync
通過-F指定列分隔符
$ # -F和:之間沒有空格
$ awk -F: '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt
root /root /bin/bash
daemon /usr/sbin /usr/sbin/nologin
bin /bin /usr/sbin/nologin
sys /dev /usr/sbin/nologin
sync /bin /bin/sync
$
$ # -F和:之間有空格, 這時分隔符最好放到引號中, 否則使用#等分隔時會報錯.
$ awk -F ':' '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt
root /root /bin/bash
daemon /usr/sbin /usr/sbin/nologin
bin /bin /usr/sbin/nologin
sys /dev /usr/sbin/nologin
sync /bin /bin/sync
通過-v FS指定列分隔符
$ awk -v FS=: '{printf "%-6s %-9s %s\n", $1, $6, $7}' demo.txt
root /root /bin/bash
daemon /usr/sbin /usr/sbin/nologin
bin /bin /usr/sbin/nologin
sys /dev /usr/sbin/nologin
sync /bin /bin/sync
3. pattern {action}
awk_script由pattern和Action組成,
例如:
awk 'BEGIN {action1} pattern {action2} END {action3}' filename
模式:有4種模式
- /正則表示式/
- 關係表示式:使用運算子進行操作, 比如字串、數字的比較測試.
- 模式匹配表示式:用運算子:~和~!, 分別表示匹配、不匹配.
- BEGIN/END語句塊、pattern語句塊.
action:由一個或多個命令/函式/表示式組成, 它們之間用換行符或分號隔開.
action主要有以下型別:
- 變數或陣列賦值
- 輸出命令
- 內建函式
- 控制流語句
注意:
- BEGIN {action1}, 只在開始執行一次, 是可選的, 預設無BEGINaction.
- pattern {action2}, 對匹配pattern的行進行操作, pattern是可選的, 預設對每一行進行action2, {action2}也是可選的, 預設列印匹配pattern的行, 但是pattern和{action2}必須出現一個, 不能都省略.
- END {action3}, 只在結尾執行一次, 是可選的, 預設無END action.
例子1:
輸入檔案內容:
$ cat a.txt
line first 1
line second 2
line third 3
line forth 4
line fifth 5
line sixth 6
line seventh 7
使用BEGIN、END等
$ # 在BEGIN的action中, 先列印一行內容, 再給i賦初值
$ # 在遍歷line的語句中, 列印第2、3列, 並對第3列累加
$ # 在END的action中, 列印第3列的累加結果
$ awk 'BEGIN {print "C2", "C3"; i=0} {print $2, $3; i+=$3} END {print "total=",i}' a.txt
C2 C3
first 1
second 2
third 3
forth 4
fifth 5
sixth 6
seventh 7
total= 28
注意:
- 在print語句中,
字串要寫在雙引號裡,
字串之間用逗號分隔,
變數可以直接賦初值,
變數使用時不能帶雙引號 - 變數賦值和使用時不需要帶$號($1/$2等不受此限制)
- 多個action語句之間使用分號分隔.
4. 運算子
類別 | 運算子 | 說明 |
---|
例: 只處理奇數行並輸出
$ awk -F: 'NR%2==1 {printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt
1) root /root /bin/bash
3) bin /bin /usr/sbin/nologin
5) sync /bin /bin/sync
例: 只處理$1等於root或bin的行, 使用||
$ awk -F: '$1=="root"||$1=="bin" {printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt
1) root /root /bin/bash
3) bin /bin /usr/sbin/nologin
5. 內建變數
範圍 | 內建變數 | 說明 |
---|
例: 使用NF, NF表示欄位數, 本例中NF=7, $NF即$7表示最後一個欄位, $(NF-1)表示倒數第二欄位
$ awk -F: '{printf "%-6s %-9s %s\n", $1, $(NF-1), $NF}' demo.txt
root /root /bin/bash
daemon /usr/sbin /usr/sbin/nologin
bin /bin /usr/sbin/nologin
sys /dev /usr/sbin/nologin
sync /bin /bin/sync
例: 使用NR, NR表示當前行的行號
$ awk -v FS=: '{printf "%s) %-6s %-9s %s\n", NR, $1, $(NF-1), $NF}' demo.txt
1) root /root /bin/bash
2) daemon /usr/sbin /usr/sbin/nologin
3) bin /bin /usr/sbin/nologin
4) sys /dev /usr/sbin/nologin
5) sync /bin /bin/sync
6. 變數
awk中, 變數不需要定義就可以直接使用, 變數型別可以是數字或字串.
例:如果第一個域匹配test, 則把第二第三個域相加並列印.
awk '$1 ~ /test/ {count=$2+$3; print count}' filename
域變數可以修改:
例: 如果第一個域等於"root", 則把它賦值為test並列印.
awk '$1=="root" {$1="test"; print}' filename
7. 條件語句
if語句
如果第三個域大於3, 則列印一個第二第三域和一個"match"字元, 各字元之間可以有空格, 也可以沒有, 字串要寫到雙引號中.
awk '{if ($3>3) print $2 "\t" $3 "\t" "match"}' a.txt
if-else if-else語句
有多個分支, 各分支的語句要寫在大括號中.
awk '{if ($3<=2) {print "0~2"} else if ($3<=4) {print "3~4"} else {print "5~n"}}' a.txt
8. 迴圈語句
- awk有三種迴圈:while、for、special for
- 可以使用break和continue.
- next語句從輸入檔案中讀取一行, 然後從頭開始執行awk指令碼.
- exit語句用於結構awk程式, 但不會略過END塊.
例子:
awk '{i=1; while(i<=NF){print i, $i; i++}; print "------"}' a.txt
說明:
- NF是當前行(記錄)的欄位(域)數量, $i是第i個欄位(從1開始).
- 注意:print語句中, i和$i是不同的東西, i是迴圈變數, $i是第i個欄位.
- 本例以欄位數為迴圈條件, 遍歷每個欄位並列印.
例子:
awk '{for (i=1;i<=NF;i++) {print i, $i}; print "------"}' a.txt
說明:作用同上, 將while語句改為for語句實現.
special for用來遍歷關聯陣列.見關聯陣列.for(i in name) {print i, name[i]}
9. 陣列
在awk中資料的下標可以是數字, 也可以是字母(稱為關聯陣列, 類似於python中的字典).
例子:
awk '{name[i++]=$2} END {for (i=0;i<NR;i++) {print i, name[i]}}' a.txt
說明:
- 將每行的第二欄位存入陣列, 在結尾遍歷陣列並列印.
- name是一個數組, 不用宣告, 直接賦值.
- 給陣列賦值時, 直接對下標賦值, 不需要管該下標是否存在.
- 陣列下標變數i自動初始化為0, 然後每處理一個記錄自動加1.
- NR是當前行的行號(從1開始), 在END塊中NR自動變成總行數, 用來遍歷陣列.
例子:
awk '/s/ {name[NR]=$2} END {for(i in name) {print i, name[i]}}' a.txt
說明:
- 如果某行匹配/s/, 則給陣列賦值, 下標是行號, 值是$2, 在結尾遍歷陣列.
- name的下標雖然是數字, 但可以是不連續的.
10. 內建函式
https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html#Built_002din
函式 | 作用 |
---|---|
toupper() | 字串轉為大寫 |
tolower() | 字串轉為小寫 |
length() | 返回字串長度 |
substr() | 返回子字串 |
sin() | 正弦 |
cos() | 餘弦 |
sqrt() | 平方根 |
rand() | 隨機數 |
例: 使用toupper()將第一欄位轉為大寫
$ awk -F: '{printf "%s) %-6s %-9s %s\n", NR, toupper($1), $(NF-1), $NF}' demo.txt
1) ROOT /root /bin/bash
2) DAEMON /usr/sbin /usr/sbin/nologin
3) BIN /bin /usr/sbin/nologin
4) SYS /dev /usr/sbin/nologin
5) SYNC /bin /bin/sync