Sed&awk筆記之awk篇:快速瞭解Awk(一)
Awk是什麼
Awk、sed與grep,俗稱Linux下的三劍客,它們之間有很多相似點,但是同樣也各有各的特色,相似的地方是它們都可以匹配文字,其中sed和awk還可以用於文字編輯,而grep則不具備這個功用。sed是一種非互動式且面向字元流的編輯器(a “non-interactive” stream-oriented editor),而awk則是一門模式匹配的程式語言,因為它的主要功能是用於匹配文字並處理,同時它有一些程式語言才有的語法,例如函式、分支迴圈語句、變數等等,當然比起我們常見的程式語言,Awk相對比較簡單。 使用Awk,我們可以做以下事情:
- 將文字檔案視為由欄位和記錄組成的文字資料庫;
- 在操作文字資料庫的過程中能夠使用變數;
- 能夠使用數學運算和字串操作
- 能夠使用常見的程式設計結構,例如條件分支與迴圈;
- 能夠格式化輸出;
- 能夠自定義函式;
- 能夠在awk指令碼中執行UNIX命令;
- 能夠處理UNIX命令的輸出結果;
裝備以上功能,awk能夠做得事情非常多。但千里之行,始於足下,我們首先從最基本的命令列語法開始,一步一步得走入awk的程式設計世界。
命令列語法
同sed一樣,awk的命令列語法也有兩種形式:
awk [-F ERE] [-v assignment] ... program [argument ...]
awk [-F ERE] -f progfile ... [-v assignment] ...[argument ...]
這裡的program類似sed中的script,因為我們一直強調awk是一門程式語言,所以將awk的指令碼視為一段程式碼。而awk的指令碼同樣可以寫到一個檔案中,並通過-f引數指定,這一點和sed是一樣的。program一般多個pattern和action序列組成,當讀入的記錄匹配pattern時,才會執行相應的action命令。這裡有一點要注意,在第一種形式中,除去命令列選項外,program引數一定要位於第一個位置。 Awk的輸入被解析成多個記錄(Record),預設情況下,記錄的分隔符是
,因此可以認為一行就是一個記錄,記錄的分隔符可以通過內建變數RS
更改。當記錄匹配某個pattern時,才會執行後續的action命令。 而每個記錄由進一步地被分隔成多個欄位(Field),預設情況下欄位的分隔符是空白符,例如空格、製表符等等,也可以通過-F ERE
選項或者內建變數FS
更改。在awk中,可以通過$1,$2…來訪問對應位置的欄位,同時$0存放整個記錄,這一點有點類似shell下的命令列位置引數。關於這些內容,我們會在下面詳細介紹,這裡你只要知道有這些東西就好。 標準的awk命令列引數主要由以下三個:
-
-F ERE
:定義欄位分隔符,該選項的值可以是擴充套件的正規表示式(ERE); -
-f progfile
:指定awk指令碼,可以同時指定多個指令碼,它們會按照在命令列中出現的順序連線在一起; -
-v assignment
:定義awk變數,形式同awk中的變數賦值,即name=value,賦值發生在awk處理文字之前;
為了便於理解,這裡舉幾個簡單的例子。通過-F引數設定冒號:為分隔符,並列印各個欄位:
[kodango@devops ~]$ echo "1:2:3" | awk -F: `{print $1 " and " $2 " and " $3}`
1 and 2 and 3
在awk的指令碼中訪問通過-v選項設定的變數:
[kodango@devops ~]$ echo | awk -v a=1 `BEGIN {print a}`
1
從上面可以看到,通過-v選項設定的變數在BEGIN
的位置就可以訪問了。BEGIN
是一個特殊的pattern,它在awk處理輸入之前就會執行,可以認為是一個初始化語句,與此對應的還有END
。 好像還沒介紹如何指定處理的檔案,是不是最後的argument就是指定的檔案?在看我這本書之前,我也是這樣認為的,但是實際上arguemnt有兩種形式,它們分別是輸入檔案(file)和變數賦值(assignment)。 awk可以同時指定多個輸入檔案,如果輸入檔案的檔名為`-`,表示從標準輸入讀取內容。 變數賦值類似-v選項,它的形式為name=value。awk中的變數名同一般的程式語言無太多區別,但是不能同awk的保留關鍵字重名,可以檢視awk的man手冊查詢哪些是保留關鍵字。而變數值只有兩種形式:字串和數值。變數賦值必須位於指令碼引數的後面,與檔名引數無先後順序的要求,但是位於不同位置的賦值它的執行時機是不同的。 我們用實際的例子來解釋這個區別,假設有兩個檔案:a和b,它們的內容分別如下所示:
[kodango@devops awk_temp]$ cat a
file a
[kodango@devops awk_temp]$ cat b
file b
為了說明賦值操作發生的時機,我們在BEGIN,正常處理,END三個地方都列印變數的值。 第一種情況: 變數賦值位於所有檔名引數之前
[kodango@devops awk_temp]$ awk `BEGIN {print "BEGIN: " var} {print "PROCESS: " var}
END {print "END: " var }` var=1 a
BEGIN:
PROCESS: 1
END: 1
結果:賦值操作發生在正常處理之前,BEGIN
動作之後。 第二種情況:變數賦值位於所有檔名之後:
[kodango@devops awk_temp]$ awk `BEGIN {print "BEGIN: " var} {print "PROCESS: " var}
END {print "END: " var }` a var=1
BEGIN:
PROCESS:
END: 1
結果:賦值操作發生在正常處理之後,END
動作之前。 第三種情況:變數賦值位於檔名之間:
[kodango@devops awk_temp]$ awk `BEGIN {print "BEGIN: " var} {print "PROCESS: " var}
END {print "END: " var }` a var=1 b
BEGIN:
PROCESS:
PROCESS: 1
END: 1
結果:賦值操作發生在處理前面的檔案之後,並且位於處理後面的檔案之前; 總結如下:
- 如果變數賦值在第一個檔案引數之前,在
BEGIN
動作之後執行,影響到正常處理和END
動作; - 如果變數賦值在最後一個檔案引數之後,在END動作之前執行,僅影響
END
動作; - 如果檔案引數不存在,情況同1所述;
- 如果變數賦值位於多個檔案引數之間,在變數賦值前面的檔案被處理後執行,影響到後續檔案的處理和
END
動作;
所以變數賦值一定要考慮清楚用途,否則比較容易出錯,不過一般情況下也不會用到變數賦值。 自然地大家會將變數賦值與-v assignment選項進行比較,賦值的形式是一致的,但是-v選項的執行時機比變數賦值要早:
[kodango@devops awk_temp]$ echo 1 | awk -v var=a `BEGIN {print "BEGIN: " var}`
BEGIN: a
可見,-v選項的賦值操作在BEGIN
動作之前就執行了。 變數賦值一定要小心不要與保留關鍵字重名,否則會報錯:
[kodango@devops awk_temp]$ echo 1 | awk -v BEGIN=1 `BEGIN {print "BEGIN: " BEGIN}`
awk: fatal: cannot use gawk builtin `BEGIN` as variable name
本篇文章主要介紹了awk的命令列語法,下一篇的主題是awk語言的基礎元素與概念。
相關文章
- 《sed & awk》讀書筆記之 awk 篇筆記
- AWK 學習筆記筆記
- Linux awk基礎筆記Linux筆記
- 【shell筆記>命令】grep,sed,awk筆記
- linux之shell awk 之一Linux
- linux之 awkLinux
- linux之awkLinux
- 學習sed & awk時做的筆記筆記
- awk命令詳解
- 5分鐘帶你瞭解Linux awk命令!Linux
- 【Linux篇】--awk的使用Linux
- linux之awk用法Linux
- Linux awk小記Linux
- awk
- Linux三劍客之awk詳解Linux
- awk sed 用法詳解
- 技能篇:awk教程-linux命令Linux
- Awk split
- awk命令
- gsub in awk
- Linux awk 命令詳解Linux
- linux awk 命令詳解Linux
- linux awk命令詳解Linux
- sqlldr+awk+shell的一次記錄SQL
- awk 系列:如何讓 awk 使用 Shell 變數變數
- linux之shell awk 之二Linux
- AWK學習一例
- Linux中awk命令詳解Linux
- [轉]linux awk命令詳解Linux
- Linux awkLinux
- awk -- kill sessionSession
- awk變數變數
- AWK 學習
- awk常用案例
- Linux 三劍客之 awk 實戰詳解教程Linux
- awk小技巧之執行shell命令
- Linux三大劍客之awkLinux
- android開發指令碼之awkAndroid指令碼