七.Linux之awk命令

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

n代表第n個域,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將會使得"請輸入姓名:"瘋狂輸出,原因還尚未琢磨清楚

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章