1. 寫在前面
本文主要介紹 Linux “awk” 命令:“awk” 是另一個強大的文本處理工具,用于處理和操作結構化數據,如日志文件和命令輸出。它可以根據需要為我們打印特定的列值。
公眾號: 滑翔的紙飛機
2. awk 命令
我們能用 awk 做什么?awk 處理文本數據,不管是從文件來的或者數據流中來的。輸入數據被區分為記錄和文本域。 awk 一次處理一條記錄,一直到輸入結束。
- awk 操作:
(1) 逐行掃描文件;
(2) 將每個輸入行分割成字段;
(3) 將輸入行/字段與匹配規則進行比較;
(4) 對匹配的行執行操作;
- 適用于:
(1) 轉換數據文件;
(2) 生成格式化報告;
- 編程結構:
(1) 輸出行格式化;
(2) 算術和字符串運算;
(3) 條件和循環;
awk 命令的基本語法是:
awk [ -F fs ] [ -v var=value ] [ 'prog' | -f progfile ] [ file ... ]
-F fs
:指定輸入文件折分隔符,fs是一個字符串或者是一個正則表達式,如-F:;
-f program-file
:從腳本文件中讀取awk命令;
-v
: 后跟var=value,賦值一個用戶定義變量;
備注: 示例文本文件:text.txt、text2.txt
cat > ./text.txt
---------------------------------------------------
Dwight Frances manager account 45000
Lindsay Max clerk account 25000
Jo Richardson manager sales 50000
Rosalind Watt manager account 47000
Gale Evelina peon sales 15000
Baron Eveline clerk sales 23000
Will Pater peon sales 13000
Christopher Noah director purchase 80000
cat > ./text2.txt
---------------------------------------------------
A B CTarun A12 1
Man B6 2
Praveen M42 3
2.1 簡單示例
(1)awk 的默認行為
默認情況下,awk 會打印指定文件中的每一行數據。
root@dev:~/linux# awk '{print}' text.txt
---------------------------------------------------
Dwight Frances manager account 45000
Lindsay Max clerk account 25000
Jo Richardson manager sales 50000
Rosalind Watt manager account 47000
Gale Evelina peon sales 15000
Baron Eveline clerk sales 23000
Will Pater peon sales 13000
Christopher Noah director purchase 80000
在上述示例中,沒有給出任何模式。因此操作適用于所有行。不帶任何參數的 print
參數默認打印整行,因此它可以打印文件的所有行,不會出現失敗。
(2)打印與給定模式匹配的行
root@dev:~/linux# awk '/manager/ {print}' text.txt
---------------------------------------------------
Dwight Frances manager account 45000
Jo Richardson manager sales 50000
Rosalind Watt manager account 47000
在上例中,awk 命令會打印所有與 "manager "匹配的行。
**備注:**一個正則表達式匹配一系列字符串。awk 正則表達式樣式使用//
來包裹,可以是任何一種其他的正則表達式。這是一個例子,打印任何以兩個或者更多數字開頭的記錄的第一個文本域:
root@dev:~/linux# awk '/^[A-B][a-z]/ { print $1,$2 }' text.txt
---------------------------------------------------------------
Baron Eveline
(3)將一行拆分為多個字段
對于每條記錄(即行),awk 命令默認以空格字符分割記錄,并將其存儲在 $n
變量中。如果一行有 4 個字段,則分別存儲在 $1、$2、$3 和 $4
中。另外,$0
代表整行。
root@dev:~/linux# awk '{print $1,$2,$5}' text.txt
---------------------------------------------------
Dwight Frances 45000
Lindsay Max 25000
Jo Richardson 50000
Rosalind Watt 47000
Gale Evelina 15000
Baron Eveline 23000
Will Pater 13000
Christopher Noah 80000
在上例中,$1,$2
和 $5
分別代表姓名和薪金字段。
(4)打印文本中每一行的第一個字段以及用"-"分隔的行號
root@dev:~/linux# awk '{print NR " - " $1,$2 }' text.txt
-------------------------------------------------------------
1 - Dwight Frances
2 - Lindsay Max
3 - Jo Richardson
4 - Rosalind Watt
5 - Gale Evelina
6 - Baron Eveline
7 - Will Pater
8 - Christopher Noah
在上例中,$1,$2
代表姓名輸出行號,“ - ”進行分割;
(5)如果存在,打印任何空行
root@dev:~/linux# awk 'NF == 0 {print NR}' text2.txt
-------------------------------------------------------------
2
或者
root@dev:~/linux# awk 'NF <= 0 {print NR}' text2.txt
-------------------------------------------------------------
2
(6) 查找文件中最長一行的長度
root@dev:~/linux# awk '{ if (length($0) > max) max = length($0) } END { print max }' text.txt
-------------------------------------------------------------------------------------
40
(7) 計算文件中的行數
root@dev:~/linux# awk 'END { print NR }' text.txt
------------------------------------------------------------------
8
(8) 打印超過 35 個字符的行
root@dev:~/linux# awk 'length($0) > 35' text.txt
------------------------------------------------------------------
Dwight Frances manager account 45000
Christopher Noah director purchase 80000
(9) 查找/檢查任何特定列中的任何字符串
root@dev:~/linux# awk '$1 == "Dwight" { print $0 }' text.txt
------------------------------------------------------------------
Dwight Frances manager account 45000或者:
root@dev:~/linux# awk '{ if($1 == "Dwight") print $0;}' text.txt
------------------------------------------------------------------
Dwight Frances manager account 45000
(10)打印從 1 到 n 的第一個數字的平方,例如 6
root@dev:~/linux# awk 'BEGIN { for(i=1;i<=6;i++) print "square of", i, "is",i*i; }'
--------------------------------------------------------------------------------
square of 1 is 1
square of 2 is 4
square of 3 is 9
square of 4 is 16
square of 5 is 25
square of 6 is 36
(11) 計算文件大小
root@dev:~/linux# ls -l *.txt | awk '{sum+=$5} END {print sum}'
------------------------------------------------------------------
336
(12) 匹配包含 “manager” 直到 “account"記錄
root@dev:~/linux# awk '/manager/,/account/ { print $0 }' text.txt
------------------------------------------------------------------
Dwight Frances manager account 45000
Jo Richardson manager sales 50000
Rosalind Watt manager account 47000
2.2 awk 中的內置變量
awk 的內置變量包括字段變量–$1、$2、$3
等($0
表示整行)–它們將一行文本分割成單個單詞或稱為字段的片段。
變量 | 描述 |
---|---|
$n | 當前記錄的第n個字段,字段間由FS分隔 |
$0 | 完整的輸入記錄 |
ARGC | 命令行參數的數目 |
ARGIND | 命令行中當前文件的位置(從0開始算) |
ARGV | 包含命令行參數的數組 |
CONVFMT | 數字轉換格式(默認值為%.6g)ENVIRON環境變量關聯數組 |
ERRNO | 最后一個系統錯誤的描述 |
FIELDWIDTHS | 字段寬度列表(用空格鍵分隔) |
FILENAME | 當前文件名 |
FNR | 各文件分別計數的行號 |
FS | 字段分隔符(默認是任何空格) |
IGNORECASE | 如果為真,則進行忽略大小寫的匹配 |
NF | 一條記錄的字段的數目 |
NR | 已經讀出的記錄數,就是行號,從1開始 |
OFMT | 數字的輸出格式(默認值是%.6g) |
OFS | 輸出字段分隔符,默認值與輸入字段分隔符一致 |
ORS | 輸出記錄分隔符(默認值是一個換行符) |
RLENGTH | 由match函數所匹配的字符串的長度 |
RS | 記錄分隔符(默認是一個換行符) |
RSTART | 由match函數所匹配的字符串的第一個位置 |
SUBSEP | 數組下標分隔符(默認值是/034) |
2.2.1 示例
(1)使用 NR 內置變量(顯示行號)
root@dev:~/linux# awk '{print NR,$0}' text.txt
---------------------------------------------------
1 Dwight Frances manager account 45000
2 Lindsay Max clerk account 25000
3 Jo Richardson manager sales 50000
4 Rosalind Watt manager account 47000
5 Gale Evelina peon sales 15000
6 Baron Eveline clerk sales 23000
7 Will Pater peon sales 13000
8 Christopher Noah director purchase 80000
在上例中,帶有 NR 的 awk 命令會打印所有行以及行號。
(2)使用 NF 內置變量(顯示最后字段)
root@dev:~/linux# awk '{print $1,$2,$NF}' text.txt
Dwight Frances 45000
Lindsay Max 25000
Jo Richardson 50000
Rosalind Watt 47000
Gale Evelina 15000
Baron Eveline 23000
Will Pater 13000
Christopher Noah 80000
在上例中,$1,$2
代表姓名,$NF
代表薪金。我們可以使用 $NF
獲取薪金,其中 $NF
代表最后一個字段。
(3) NR 內置變量的另一種用法(顯示行從 3 到 6行)
root@dev:~/linux# awk 'NR==3, NR==6 {print NR,$0}' text.txt
3 Jo Richardson manager sales 50000
4 Rosalind Watt manager account 47000
5 Gale Evelina peon sales 15000
6 Baron Eveline clerk sales 23000
在上例中,顯示3 ~ 6行記錄,顯示行號;
(4) 忽略大小寫
root@dev:~/linux# awk 'BEGIN{IGNORECASE=1} /evelina/' text.txt
-----------------------------------------------------------------------
Gale Evelina peon sales 15000root@dev:~/linux# awk 'BEGIN{IGNORECASE=1} /Evelina/' text.txt
-----------------------------------------------------------------------
Gale Evelina peon sales 15000
(5) 打印文件名及行數
root@dev:~/linux# awk 'END { print "File", FILENAME, "contains", NR, "lines." }' text.txt
-----------------------------------------------------------------------------------
File text.txt contains 8 lines.
更多示例后續不斷補充。