[Shell] awk初學之常見問題

tolilong發表於2016-05-20
awk初學之常見問題 
(轉載)


1. awk ‘{code}1’ 中的“1”是幹什麼的?
一個完整的awk語句為:Awk ‘[patten]{action}……’, 其中pattern預設為1,action預設為{print}.
那麼awk ‘1’完整的寫法就是awk ‘1{print}’; 同理,awk ‘{print}’完整的寫法也是awk ‘1{print}’.


2. NR和FNR的區別是啥?
NR: 當前行記錄數。
FNR: 當前檔案的行記錄數。
當awk處理的檔案數超過1時,NR和FNR才會有區別。例如:
cat file
a
b
c
d
e
f


awk '{print "NR = " NR "  FNR = " FNR, $0}' file
NR = 1  FNR = 1 a
NR = 2  FNR = 2 b
NR = 3  FNR = 3 c
NR = 4  FNR = 4 d
NR = 5  FNR = 5 e
NR = 6  FNR = 6 f


awk '{print "NR = " NR "  FNR = " FNR, $0}' file file
NR = 1  FNR = 1 a
NR = 2  FNR = 2 b
NR = 3  FNR = 3 c
NR = 4  FNR = 4 d
NR = 5  FNR = 5 e
NR = 6  FNR = 6 f
NR = 7  FNR = 1 a
NR = 8  FNR = 2 b
NR = 9  FNR = 3 c
NR = 10  FNR = 4 d
NR = 11  FNR = 5 e
NR = 12  FNR = 6 f




3. Awk怎麼引入變數?
有兩種方法:
1: awk -v var=$VAR '{code}'
2: awk '{CODE}'$VAR'{CODE}'
例如:
VAR=XXX


awk -v var=$VAR 'BEGIN{print var}'
XXX


awk 'BEGIN{print "'$VAR'"}'
XXX


推薦使用第一種方法,這樣可以避免一些不必要的煩惱。如


4. 為什麼OFS不起作用?
先看一個例子:
echo 'aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd' |awk -v OFS="|" '{print $0}'
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd


上面的例子中OFS為什麼沒有生效呢,原因是OFS指的是輸出欄位分隔符,所以必須對欄位進行操作時OFS才會起作用,正確的方法應該是:
echo 'aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd' |awk -v OFS="|" '{$1=$1;print $0}'
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd


正如Tim大師所講的,$1=$1這個action,是我們對awk撒的謊,目的就是為了使得OFS生效,除此之外,NF+=0也是常用的方法。




5. 同樣的程式碼,別人執行成功,為什麼我執行失敗?
這個問題的原因很多,我這裡列舉兩個最常見的,大家可以補充。
1: awk版本引起的,如gawk中的一些擴充套件函式或變數,在nawk中沒有,或是不同版本的(g/n)awk也會有差別,這樣情況需要重新編寫。
2: 文字格式的問題,cat-A file檢視一下,如果是,dos2unix應該可以解決。
注:書寫錯誤也有可能哦


6. Awk 語句中可以使用{n,m}這樣的正則麼?
可以,使用方法:gawk -- re-interval ,其它版本使用方法會有所不同,請大家補充


7. BEGIN 和END 到底是怎麼一回事?
有時,對於新手可能也會是個問題。簡單說下:
BEGIN {action} : 讀取文字之前進行的操作。要避免類似下面的寫法:
awk 'BEGIN{ filename =  FILENAME}' file
# or:
awk 'BEGIN{FS=":"; for(i=2;i<=NF;i++) print $i}' file
 


如果BEGIN 模組中使用getline函式時,情況會有所不同:
cat file
1
2
3
4
5


awk 'BEGIN{while (getline <"file") print}' file
1
2
3
4
5
 
END {action}: 
它在整個輸入檔案處理完成後被執行,同樣無法對文字進行任何操作,如匹配某個pattern執行action。


8. print,printf 和sprintf?
print:為一般的列印
printf:可以定義列印格式
sprintf:可以完成和printf相同的功能,不同的是sprintf只能輸出值,並不能完成列印的功能。


print預設有個換行\n,
而printf沒有,當然它和C語言的printf類似(awk本是c的近親),能列印各種格式,但預設沒有換行。


例如:
awk 'BEGIN{var=123; print "var = " var}'
var = 123


awk 'BEGIN{var=123;printf "%s %5f\n", "var =",var}'
var = 123.000000


awk 'BEGIN{var=123;sprintf ("%s  %5f\n", "var =",var)}'




awk ‘BEGIN{var1=123;var2=sprintf ("%5f",var1); print "var2 =" var2}’
var2 = 123.000000


9. “a==b?c:d” ?
這個是一個if語句的簡寫,即conditional expression1 ? expression2: expression3;完整寫法為:
if(a==b) {c} else {d}


10. awk ‘! a[$0]++’ 怎麼理解?
這是一個非常經典的去重複項的awk語句,雖然短小,不過涉及到了不少知識點,下面一一解讀:
1 :”!” 即非。
2:a[$0],以$0為資料下標,建立陣列a
3:a[$0]++,即給陣列a賦值,a[$0]+=1
4 :那麼組合起來,awk是怎麼執行!a[$0]++的呢?我用一個實際例子來解釋:
cat file
111
222
111
222
333


awk '{print a[$0],!a[$0]++,a[$0],!a[$0],$0}' file
  1 1 0 111
  1 1 0 222
1 0 2 0 111
1 0 2 0 222
  1 1 0 333




原來,第一個a[$0]的值為空,所以!a[$0]++是先作判斷,結果為1(非空為真,即為1),再作陣列賦值a[$0]++。這也就是為什麼前面的!a[$0]++並不一定等於後面的!a[$0]。
awk ‘++a[$0]==1’ 和上面的程式碼作用一樣,你理解了麼?


11. 如何列印單雙引號?
awk 'BEGIN {print "single quote --> '\''";print "double quote --> \"" }'
single quote --> '
double quote --> "






更可靠的的方法如Tim所示:
awk 'BEGIN {print "single quote --> \047";print "double quote --> \042" }'
 
12. awk 語句中多個{}是怎麼執行的?
還是用個例子來說明:
cat file
1
2
3
4
5


awk '$1==3{printf "|| "$0}{printf " @@ "$0}{print $0}' file # 這個語句中包含三個action
@@ 11   # 判斷$1==3?否;執行 action {printf " @@ "$0};執行 action {print $0}
@@ 22   # 判斷$1==3?否;執行 action {printf " @@ "$0};執行 action {print $0}
|| 3 @@ 33  # 判斷$1==3?是,執行{print “|| “$0}; 執行 action {printf " @@ "$0};執行 action {print $0}
@@ 44  # 判斷$1==3?否;執行 action {printf " @@ "$0};執行 action {print $0}
@@ 55  # 判斷$1==3?否;執行 action {printf " @@ "$0};執行 action {print $0}


這樣可以清楚的看出,awk是一行一行讀取文字,然後按照程式碼的前後順序執行。但如果action中包含next或exit時,有所不同:
awk '$1==3{printf "|| "$0;next}{printf "@@ "$0}{print $0}' file
@@ 11
@@ 22
|| 3@@ 44
@@ 55


awk '$1==3{printf "|| "$0;exit}{printf "@@ "$0}{print $0}' file
@@ 11
@@ 22
|| 3
 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24237320/viewspace-2103812/,如需轉載,請註明出處,否則將追究法律責任。