awk的調用方式與sed類似,腳本文件以#!/bin/awk -f或#!/bin/gawk -f開頭。相比於grep和sed,awk正則表達式支持"?"和"+"兩個拓展元字符。
- awk模式匹配
$ cat file
qwer
1234
[jin1ming@ML linux_shell]$ awk '/^$/{print "Hello World!"}' file
Hello World!
Hello World!
^$在此處用於匹配空行
- 記錄和域
awk認爲每行爲一個記錄,行中每個字符串爲域,域之間用空格,Tab鍵或其他符號進行分隔,分隔域的是分隔符。(分隔符默認爲空格)
$ cat phoneinfo
張三 湖南 123455
李四 山西 222222
王五 河南 333333
$ awk '{print $1}' phoneinfo
張三
李四
王五
$ awk '{print $1;{print $0}}' phoneinfo
張三
張三 湖南 123455
李四
李四 山西 222222
王五
王五 河南 333333
$ awk 'BEGIN{num=3} {print$num}' phoneinfo
123455
222222
333333
0代表所有域
awk處理時,將進行逐行掃描
BEGIN在遍歷文件前執行
awk中可使用變量
$ awk 'BEGIN{OFS=";"} {print $1,$2,$3}' phoneinfo |
> awk 'BEGIN{FS=";";OFS="::"} {print $1,$2,$3}'
張三::湖南::123455
李四::山西::222222
王五::河南::333333
OFS爲輸出域分隔符,FS爲(輸入)域分隔符
該demo,將文件中的空格作爲域分隔符進行域劃分,
將“;”作爲域分隔符進行輸出到管道,
最後將管道中的文本按“;”作爲域分隔符進行域劃分,
最後將“::”作爲輸出域分隔符進行輸出。
#修改字符串之間的空格爲兩個
$ cat phoneinfo
張三 湖南 123455
李四 山西 222222
王五 河南 333333
$ awk 'BEGIN{OFS=","}{print $1,$2,$3}' phoneinfo
張三,湖南,123455
李四,山西,222222
王五,河南,333333
說明空格作爲域分隔符時,空格可爲1個或多個
$ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
> awk 'BEGIN{FS=":";OFS=","} {print $1,$2,$3}'
張三,,湖南
李四,,山西
王五,,河南
$ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
> awk 'BEGIN{FS="::";OFS=","} {print $1,$2,$3}'
張三,湖南,123455
李四,山西,222222
王五,河南,333333
其他符號作爲域分隔符只代表其一個字符,若想多個,必須使用“+”,
例如 \t+代表一個或多個該字符(支持正則)
注意此處第一個命令,輸出中第二個域爲空域
$ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
> awk 'BEGIN{FS="::";OFS=",";ORS=";"}
> {print $1,$2,$3}'
張三,湖南,123455;李四,山西,222222;王五,河南,333333;
ORS輸出域分隔符,RS記錄分隔符(默認都爲換行符)
- 關係和布爾運算符
需注意:
1:~ 匹配正則表達式
2: !~ 不匹配正則表達式
其他運算符與c語言一致
$ awk 'BEGIN{FS=":"} $2~/dd/' 2.txt
2:dd
:ddddddd
- 表達式
統計行數
$ awk 'BEGIN{i=0} {print ++i}' 2.txt
1
2
3
4
5
計算每人平均分數
$ cat score
張三:78 92 87
李四:91 64 87
王五:34 99 56
$ cat awkdomo.awk
#!/bin/awk -f
BEGIN {FS="[: ]"}
{sum=$2+$3+$4
avg=sum/3
print $1,":",avg}
$ chmod u+x awkdomo.awk
$ ./awkdomo.awk score
張三 : 85.6667
李四 : 80.6667
王五 : 63
- 常用系統變量
以上提到的不再重複
ARGC 命令行參數的數量
ARGIND 命令行中當前文件的位置(以0開始標號)
ARGV 命令行參數的數組(ARGV[0]存儲的是執行腳本的程序名)
FILENAME 當前文件名
NF 當前記錄中的域數量
$ cat awkdomo.awk
#!/bin/awk -f
BEGIN{FS="[: ]"}
{print "\nARGC:",$ARGC,
"\nARGIND:",$ARGIND,
"\nARGV",$ARGV[2],
"\nFILENAME:",$FILENAME,
"\nNF:",$NF
}
$ ./awkdomo.awk score
ARGC: 78
ARGIND: 張三
ARGV 張三:78 92 87
FILENAME: 張三:78 92 87
NF: 87
ARGC: 91
ARGIND: 李四
ARGV 李四:91 64 87
FILENAME: 李四:91 64 87
NF: 87
ARGC: 34
ARGIND: 王五
ARGV 王五:34 99 56
FILENAME: 王五:34 99 56
NF: 56
- 格式化輸出
printf (格式控制符,參數) ,與c語言一致 - 內置字符串函數
gsub(r,s) 在輸入文件中用s替換r(全局替換)
gsub(r,s,t) 在t行中用s替換r
index(s,t) 返回s中字符串第一個t的位置
length(s) 返回s的長度
match(s,t) 測試s是否包含匹配t的字符串
split(r,s,t) 以t爲分隔符將r進行分割,保存到數組s
sub(r,s,t) 將t中第一次出現的r替換爲s
substr(r,s) 返回字符串r中從s開始的後綴部分
substr(r,s,t) 返回字符串r中從s開始長度爲t的後綴部分
- 向awk腳本傳遞參數
awk -f 腳本文件 parameter=value 輸入文件
或
awk [awk命令] parameter=value 輸入文件
$ awk '
BEGIN{n = 999; print n}
{if (n==1) print "Continue!"
} ' n=1 2.txt
999
Continue!
Continue!
Continue!
Continue!
Continue!
參數賦值在BEGIN後執行
- 條件語句和循環語句
和c語言完全一致,在判斷時可以使用~匹配符和正則表達式作爲if語句的條件 - 數組
awk數組的形式和c語言一致,只是無需定義就可以使用,需要注意的是數組下標不是必須爲整數,可以爲浮點數或字符串,而且09和9作爲下標是不一樣的
$ awk '
BEGIN{nums[1.5]=5.1} {print nums[1.5];print nums[1]}
' score
5.1
5.1
5.1
$ awk '
BEGIN{nums[wer]=9;nums[2]=2;nums[9]=9}
END {for (var in nums)
print var,":",nums[var]
}' score
: 9
9 : 9
2 : 2
數組和參數相結合的根據姓名查詢個人信息
$ cat awkdomo2.awk
#!/bin/awk -f
BEGIN{
if(ARGC>2){
name=ARGV[1];
delete ARGV[1] }
else{
while(!name){
print "請輸入姓名:";
getline name< "-"}
}
}
$1~name {print $1,$2,$3}
./awkdomo2.awk 張三 phoneinfo
張三 湖南 123455
輸入姓名使用read將會使得"請輸入姓名:"瘋狂輸出,原因還尚未琢磨清楚