Linux Shell 程式設計之gawk詳解
awk 簡史:
The name awk comes from the initials of its designers:A lfred V. Aho, Peter J.W einberger, and Brian W.K ernighan. The original version of awk was written in 1977 at AT&T Bell Laboratories.
gawk 簡史:
Paul Rubin wrote gawk in 1986. Jay Fenlason completed it, with advice from Richard Stallman. John Woods contributed parts of the code as well. In 1988 and 1989, David Trueman, thoroughly reworked gawk for compatibility with the newer awk.
gawk 是 awk 的 GNU 版本。是一個功能更加強大的具有程式設計擴充套件性的工具。
gawk 的命令格式
gawk options program file
簡單的對 options 做個介紹:
-F fs : 指定航中分割資料欄位的欄位分隔符 -f file: 指定讀取程式的檔名。多行命令可以放在一個檔案以便複用 -v var=value:指定 gawk 程式中一個變數以及其預設值 -mf N:指定要處理的資料檔案中的最大欄位數 -mr N:指定資料檔案中的最大資料行數 -W keyword: 指定 gawk 的相容模式或警告等級
gawk 的命令程式設計
gawk 的中心是其命令,可以有兩種方式來呼叫命令
命令列的呼叫方式;
將多行命令編寫在檔案的呼叫方式
命令列的呼叫方式:
[root@CentOS00 _data] # gawk '{print "hello, world!"} ' _
要注意的是兩點:
'{}' 成為 gawk 的固定格式,{} 是放置 gawk 命令的地方,而'' 是將命令當做字串與其他選項或引數字串隔離的分隔符。
[root@centos00 _data] # gawk 'print "hello, world!" ' gawk: cmd. line: 1 : print "hello, world!" gawk: cmd. line: 1 : ^ syntax error
[root@centos00 _data] # gawk {print "hello, world!"} bash: !"}: event not found [root@centos00 _data] #
gawk 的預設從標準輸入流來讀文字,如果沒有指定文字檔案,那就等待標準輸入流的輸入:
[ root@ centos00 _data]# gawk '{print "hello, world!"} ' this a hello world programm hello, world!
多條命令也可以寫在一行中處理,使用“;”分隔符即可:
[root @centos 00 _data]# gawk -F: '{ $6 = $1 ":" $6 ; print $1 "' 's home director is " $6 } ' /etc/passwd roots home director is root:/root bins home director is bin:/bin daemons home director is daemon:/sbin adms home director is adm:/ var /adm lps home director is lp:/ var /spool/lpd syncs home director is sync :/sbin
對單引號"'"做轉義的時候,使用兩次單引號即可,而不是使用"\".
gawk 的功能也是對每行輸入做處理。
將多行命令編寫在檔案的呼叫方式
[root@centos00 _data] # gawk -F: -f getUserDirectory.awk /etc/passwd
[root@centos00 _data] # cat getUserDirectory.awk { print $ 1 "'s home directory is " $ 6 } [root@centos00 _data] # gawk -F: -f getUserDirectory.awk /etc/passwd root 's home directory is /root bin' s home directory is /bin daemon 's home directory is /sbin adm' s home directory is /var/adm lp 's home directory is /var/spool/lpd
多行命令寫在檔案中:
[root@centos00 _data] # cat getUserDirectory.awk {$6 = $1 ":" $6 } { print $1 "'s home directory is " $6 } [root@centos00 _data] # gawk -F: -f getUserDirectory.awk /etc/passwd root 's home directory is root:/root bin' s home directory is bin: /bin daemon's home directory is daemon:/sbin
依然是用{} 來引用命令,但不需要''來分割命令字串了
1 , 2, 3 , n 是標識被-F 指定的欄位分隔符分割的欄位值。
$1 就是輸入檔案中的第一欄
gawk 的重頭戲 - “命令”武器庫
程式設計思路大家都沒大問題,針對 gawk 首先要了解的是他的武器庫,到底藏了哪些寶貝
AK-47,可靠精良,擅長短距離橫掃; M16,輕便成熟,火力猛; 沙漠之鷹,更符合隨身細帶的要求。
因此依據作戰規模,我們需要選好手上的武器:
迴圈
條件
變數
操作函式
變數
變數又可分為“內建變數”和“自定義變數”
內建變數
舉個例子來說明:
[root @centos 00 _data]# gawk -F: '{ $6 = $1 ":" $6 ; print $1 "' 's home director is " $6 } ' /etc/passwd roots home director is root:/root bins home director is bin:/bin daemons home director is daemon:/sbin
這裡的 6 就 是 內 建 變 量 , 看 得 出 來 , 字 段 索 引 內 建 變 量 需 要 用 來標記。而 6 的 6 就 是 指 文 本 文 件 中 的 第 6 列 , 以 此 類 推 , 7 就是第 7 列,且取出來之後,可以對 6 , 7 做變更。
那麼問題就來了:
是否能將內建變數取出來的值,做修改,再傳回原始檔做儲存呢?
除了 $n ( n 指代 1,2,3,4,5,6…等自然數)之外,還有一些內建變數:
FS: 輸入欄位分隔符 RS: 輸入資料行分隔符 OFS: 輸出欄位分隔符 ORS: 輸出資料行分隔符
[root@centos00 _data] # echo '32:31:33'|gawk 'BEGIN {FS= ":" ;OFS= "|" } {print $1,$2,$3}' 32 | 31 | 33
ENVIRON 也是比較有意思的內建變數用法:
[root@centos00 _data] # gawk 'BEGIN{ print ENVIRON["PATH"] }' /root/perl5/bin:/usr/lib64/qt-3.3/bin:/home/huangyun/perl5/bin:/usr/ local /bin:
更多 gawk 內建的變數,參考文件: ftp: //ftp.gnu.org/old-gnu/Manuals/gawk-3.0.3/html_chapter/gawk_11.html https: //www.gnu.org/software/gawk/manual/gawk.html#SEC_Contents
自定義變數
無法想象只有內建變數的程式設計世界會是怎麼樣,大概會像少了外掛那樣去用 visual studio code 吧,很無助。所以自定義變數是肯定會支援的
[root@centos00 _data] # gawk '{Greetings="hello world";print Greetings}' d hello world ^C [root@centos00 _data] # gawk 'BEGIN{Greetings="hello world";print Greetings}' hello world [root@centos00 _data] #
Greetings 是自定義的變數,第一個例子很有趣,沒有BEGIN 指令,gawk 始終是在等待輸入。
自定義變數之陣列
陣列在 gawk 中的使用,更像是 K-V 對:
[root@centos00 _data] # gawk 'BEGIN{ Prize[ "One" ]= "house" Prize[ "Two" ]= "iphoneX" for ( prize in Prize) { print Prize[prize] } } ' iphoneX house
變數在程式結構中是區分大小寫的!是區分大小寫的!是區分大小寫的!
結構化命令 (條件,迴圈)
# if 條件: if (condition) statement
# while 迴圈 while (condition) { statements }
# do while 迴圈 do { statements } while (condition)
# for 迴圈 # c語言風格 for (i=1;i<4;i++) { total += $i } # python 式 for ( prize in Prize) { print Prize[prize] }
已知每行欄位總數可以用內建變數 NF 標識,據此可以打印出每個欄位的值:
[root@centos00 _data] # cat testData.txt 123 345 567 789 111 222 333 444 333 555 666 777 [root@centos00 _data] # gawk '{for(i=1;i<=NF;i++){ print $i } }' testData.txt 123 345 567 789 111 222 333 444 333 555 666 777 [root@centos00 _data] #
操作函式
跟變數一樣,可分“內建函式”和“自定義函式”
內建函式參考文件即可,不需要太多的解釋。
我們該關心的還是自定義函式。
自定義函式的格式
[root@centos00 _data]# gawk ' > function getRand(myRand) > { > print myRand*rand() > } > BEGIN{ > print getRand(4) > } ' 0.95115 [root@centos00 _data]#
所有的自定義函式一定是放在 BEGIN 之前,或者說程式的開頭。
但馬上就會有問題的是,函式必須重用。重複發明不必要的輪子,是低效的。因此 gawk 給出了函式庫這個概念。
將所有的自定義函式歸檔到函式庫中,在使用個別函式時候,只要引用這個庫就可以了。相信 Java 朋友不陌生,Python 朋友簡直是秒懂,就是庫引用嘛!
[root@centos00 _data] # cat funclib.awk function myprint() { printf "%-16s - %s\n" , $1, $4 } function getRand(myRand) { print myRand* rand () } [root@centos00 _data] # cat rand.awk BEGIN{FS= ":" } { getRand(NF) } [root@centos00 _data] # gawk -f funclib.awk -f rand.awk /etc/passwd 1.66451 2.03746 5.9207 1.06546
Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx
本文永久更新連結地址:https://www.linuxidc.com/Linux/2018-09/154138.htm