awk 中的欄位、記錄和變數
這個系列的第二篇,我們會學習欄位,記錄和一些非常有用的 Awk 變數。
Awk 有好幾個變種:最早的 awk
,是 1977 年 AT&T 貝爾實驗室所創。它還有一些重構版本,例如 mawk
、nawk
。在大多數 Linux 發行版中能見到的,是 GNU awk,也叫 gawk
。在大多數 Linux 發行版中,awk
和 gawk
都是指向 GNU awk 的軟連結。輸入 awk
,呼叫的是同一個命令。GNU awk 使用者手冊中,能看到 awk
和 gawk
的全部歷史。
這一系列的第一篇文章 介紹了 awk
命令的基本格式:
$ awk [選項] '模式 {動作}' 輸入檔案
awk
是一個命令,後面要接選項 (比如用 -F
來定義欄位分隔符)。想讓 awk
執行的部分需要寫在兩個單引號之間,至少在終端中需要這麼做。在 awk
命令中,為了進一步強調你想要執行的部分,可以用 -e
選項來突出顯示(但這不是必須的):
$ awk -F, -e '{print $2;}' colours.txt
yellow
blue
green
[...]
記錄和欄位
awk
將輸入資料視為一系列記錄,通常是按行分割的。換句話說,awk
將文字中的每一行視作一個記錄。每一記錄包含多個欄位。一個欄位由欄位分隔符分隔開來,欄位是記錄的一部分。
預設情況下,awk
將各種空白符,如空格、製表符、換行符等視為分隔符。值得注意的是,在 awk
中,多個空格將被視為一個分隔符。所以下面這行文字有兩個欄位:
raspberry red
這行也是:
tuxedo black
其他分隔符,在程式中不是這麼處理的。假設欄位分隔符是逗號,如下所示的記錄,就有三個欄位。其中一個欄位可能會是 0 個位元組(假設這一欄位中不包含隱藏字元)
a,,b
awk 程式
awk
命令的程式部分是由一系列規則組成的。通常來說,程式中每個規則佔一行(儘管這不是必須的)。每個規則由一個模式,或一個或多個動作組成:
模式 { 動作 }
在一個規則中,你可以通過定義模式,來確定動作是否會在記錄中執行。模式可以是簡單的比較條件、正規表示式,甚至兩者結合等等。
這個例子中,程式只會顯示包含單詞 “raspberry” 的記錄:
$ awk '/raspberry/ { print $0 }' colours.txt
raspberry red 99
如果沒有文字符合模式,該動作將會應用到所有記錄上。
並且,在一條規則只包含模式時,相當於對整個記錄執行 { print }
,全部列印出來。
Awk 程式本質上是資料驅動的,命令執行結果取決於資料。所以,與其他程式語言中的程式相比,它還是有些區別的。
NF 變數
每個欄位都有指定變數,但針對欄位和記錄,也存在一些特殊變數。NF
變數,能儲存 awk
在當前記錄中找到的欄位數量。其內容可在螢幕上顯示,也可用於測試。下面例子中的資料,來自上篇文章文字:
$ awk '{ print $0 " (" NF ")" }' colours.txt
name color amount (3)
apple red 4 (3)
banana yellow 6 (3)
[...]
awk
的 print
函式會接受一系列引數(可以是變數或者字串),並將它們拼接起來。這就是為什麼在這個例子裡,每行結尾處,awk
會以一個被括號括起來的整數表示欄位數量。
NR 變數
另外,除了統計每個記錄中的欄位數,awk
也統計輸入記錄數。記錄數被儲存在變數 NR
中,它的使用方法和其他變數沒有任何區別。例如,為了在每一行開頭顯示行號:
$ awk '{ print NR ": " $0 }' colours.txt
1: name color amount
2: apple red 4
3: banana yellow 6
4: raspberry red 3
5: grape purple 10
[...]
注意,寫這個命令時可以不在 print
後的多個引數間新增空格,儘管這樣會降低可讀性:
$ awk '{print NR": "$0}' colours.txt
printf() 函式
為了讓輸出結果時格式更靈活,你可以使用 awk
的 printf()
函式。 它與 C、Lua、Bash 和其他語言中的 printf
相類似。它也接受以逗號分隔的格式引數。引數列表需要寫在括號裡。
$ printf 格式, 專案1, 專案2, ...
格式這一引數(也叫格式符)定義了其他引數如何顯示。這一功能是用格式修飾符實現的。%s
輸出字元,%d
輸出十進位制數字。下面的 printf
語句,會在括號內顯示欄位數量:
$ awk 'printf "%s (%d)\n",$0,NF}' colours.txt
name color amount (3)
raspberry red 4 (3)
banana yellow 6 (3)
[...]
在這個例子裡,%s (%d)
確定了每一行的輸出格式,$0,NF
定義了插入 %s
和 %d
位置的資料。注意,和 print
函式不同,在沒有明確指令時,輸出不會轉到下一行。出現轉義字元 \n
時才會換行。
Awk 指令碼程式設計
這篇文章中出現的所有 awk
程式碼,都在 Bash 終端中執行過。面對更復雜的程式,將命令放在檔案(指令碼)中會更容易。-f FILE
選項(不要和 -F
弄混了,那個選項用於欄位分隔符),可用於指明包含可執行程式的檔案。
舉個例子,下面是一個簡單的 awk 指令碼。建立一個名為 example1.awk
的檔案,包含以下內容:
/^a/ {print "A: " $0}
/^b/ {print "B: " $0}
如果一個檔案包含 awk
程式,那麼在給檔案命名時,最好寫上 .awk
的副檔名。 這樣命名不是強制的,但這麼做,會給檔案管理器、編輯器(和你)一個關於檔案內容的很有用的提示。
執行這一指令碼:
$ awk -f example1.awk colours.txt
A: raspberry red 4
B: banana yellow 6
A: apple green 8
一個包含 awk
命令的檔案,在最開頭一行加上釋伴 #!
,就能變成可執行指令碼。建立一個名為 example2.awk
的檔案,包含以下內容:
#!/usr/bin/awk -f
#
# 除了第一行,在其他行前顯示行號
#
NR > 1 {
printf "%d: %s\n",NR,$0
}
可以說,指令碼中只有一行,大多數情況下沒什麼用。但在某些情況下,執行一個指令碼,比記住,然後打一條命令要容易的多。一個指令碼檔案,也提供了一個記錄命令具體作用的好機會。以 #
號開頭的行是註釋,awk
會忽略它們。
給檔案可執行許可權:
$ chmod u+x example2.awk
執行指令碼:
$ ./example2.awk colours.txt
2: apple red 4
2: banana yellow 6
4: raspberry red 3
5: grape purple 10
[...]
將 awk
命令放在指令碼檔案中,有一個好處就是,修改和格式化輸出會更容易。在終端中,如果能用一行執行多條 awk
命令,那麼輸入多行,才能達到同樣效果,就顯得有些多餘了。
試一試
你現在已經足夠了解,awk
是如何執行指令的了。現在你應該能編寫複雜的 awk
程式了。試著編寫一個 awk 指令碼,它需要: 至少包括一個條件模式,以及多個規則。如果你想使用除 print
和 printf
以外的函式,可以參考線上 gawk 手冊。
下面這個例子是個很好的切入點:
#!/usr/bin/awk -f
#
# 顯示所有記錄 除了出現以下情況
# 如果第一個記錄 包含 “raspberry”
# 將 “red” 替換成 “pi”
$1 == "raspberry" {
gsub(/red/,"pi")
}
{ print }
試著執行這個指令碼,看看輸出是什麼。接下來就看你自己的了。
這一系列的下一篇文章,將會介紹更多,能在更復雜(更有用!) 指令碼中使用的函式。
這篇文章改編自 Hacker Public Radio 系列,一個技術社群部落格。
via: https://opensource.com/article/19/11/fields-records-variables-awk
作者:Seth Kenlon 選題:lujun9972 譯者:wenwensnow 校對:wxy
訂閱“Linux 中國”官方小程式來檢視
相關文章
- Linux 中 awk命令如何擷取指定欄位的前幾個字元Linux字元
- Linux中awk命令實現指定欄位的第一個字母大寫Linux
- 欄位修改記錄操作日誌的實現
- Django 常用欄位和引數Django
- 圓周率位數記憶記錄
- MySQL欄位新增註釋,但不改變欄位的型別MySql型別
- fastadmin 新增欄位記圖片欄位AST
- abc欄位數的使用
- Django之ORM常用欄位和引數DjangoORM
- SQL INSERT INTO 語句詳解:插入新記錄、多行插入和自增欄位SQL
- VBAP和VBEP的幾個數量欄位的說明
- Git的修改提交記錄和變基Git
- Camstar MDB setfieldex 修改建模欄位不記錄Audit TrailAI
- sql根據多個欄位查詢重複記錄SQL
- awk 語法與內建變數(一)變數
- awk 語法與內建變數(二)變數
- TensorFlow常量、變數和佔位符詳解(學習筆記)變數筆記
- MySQL資料庫查詢多個欄位值全部相同的記錄MySql資料庫
- SAP WM中階儲存型別裡的Full stk rmvl 欄位和Return Storage type欄位型別
- gson改變輸出欄位的順序
- [提問交流]模型欄位中的引數怎麼用模型
- mysql和mongodb替換欄位中某字元MySqlMongoDB字元
- python-進階教程-根據欄位將記錄分組Python
- sql語句修改欄位型別和增加欄位SQL型別
- 記錄一個關於變數命名的事情變數
- Solidity語言學習筆記————7、單位和全域性變數Solid筆記變數
- 變數與常量 - Go 學習記錄變數Go
- 記錄一下mysql多欄位排序遇到的一個好玩的現象MySql排序
- 更新一張與另一張表關聯的連線欄位記錄
- Java記憶體模型FAQ(八)Final欄位如何改變它們的值Java記憶體模型
- SQL字元型欄位按數字型欄位排序實現方法SQL字元排序
- 14億條記錄,12c 做不到2小時內變更表結構欄位型別?型別
- MySQL中變數的定義和變數的賦值使用MySql變數賦值
- Python中的全域性變數和區域性變數Python變數
- SQL Server中獲取資料庫名、表名、欄位名和欄位註釋的SQL語句SQLServer資料庫
- sql 統計多個欄位的和(如果欄位中含有 null 的處理)SQLNull
- MySQL 中 JSON 欄位的使用技巧MySqlJSON
- MySQL中JSON欄位的使用技巧MySqlJSON