SHELL的命令之a(chǎn)wk
awk命令功能是將一行分為數(shù)個(gè)“字段列”來(lái)處理,對(duì)表格化的文本處理能力超強(qiáng)。其語(yǔ)法及常用參數(shù)格式:
awk [-參數(shù) 變量] 'BEGIN{初始化} 條件類(lèi)型1{動(dòng)作1} 條件類(lèi)型2{動(dòng)作2}。。。。END{后處理}'
其中參數(shù)有:
-F re:允許awk更改其字段分隔符
-v var=$v 把v值賦值給var,如果有多個(gè)變量要賦值,那么就寫(xiě)多個(gè)-v,每個(gè)變量賦值對(duì)應(yīng)一個(gè)-v
e.g. 要打印文件a的第num行到num+num1行之間的行,
awk -v num=$num -v num1=$num1 'NR==num,NR==num+num1{print}' a
-f progfile:允許awk調(diào)用并執(zhí)行progfile程序文件,當(dāng)然progfile必須是一個(gè)符合awk語(yǔ)法的程序文件。
其中變量有:
(1)awk內(nèi)置變量:
ARGC? ? ? ? ?命令行參數(shù)的個(gè)數(shù)
ARGV?? ? ? ? 命令行參數(shù)數(shù)組
ARGIND ????當(dāng)前被處理文件的ARGV標(biāo)志符
e.g 有兩個(gè)文件a 和b,文件處理的順序是先掃描完a文件,再掃描b文件:
awk '{if(ARGIND==1){print "處理a文件"} if(ARGIND==2){print "處理b文件"}}' a b
NR ? ? 已經(jīng)讀出的記錄數(shù)
FNR?? 當(dāng)前文件的記錄數(shù)
e.g 有兩個(gè)文件a 和b,文件處理的順序是先掃描完a文件,再掃描b文件:
awk 'NR==FNR{print "處理文件a"} NR > FNR{print "處理文件b"}' a b
說(shuō)明:輸入文件a和b,由于先掃描a,所以?huà)呙鑑的時(shí)候必然有NR==FNR,然后掃描b的時(shí)候,F(xiàn)NR從1開(kāi)始計(jì)數(shù),而NR則接著a的行數(shù)繼續(xù)計(jì)數(shù),所以NR > FNR
e.g 要顯示文件的第10行至第15行
awk 'NR==10,NR==15{print}' a
FS ?輸入字段分隔符(缺省為:space:),相當(dāng)于-F選項(xiàng)
awk -F ':' '{print}' a??? 和?? awk 'BEGIN{FS=":"}{print}' a 是一樣的
OFS???? 輸出字段分隔符(缺省為:space:)
awk -F ':' 'BEGIN{OFS=";"}{print $1,$2,$3}' b
如果cat b為
1:2:3
4:5:6
那么把OFS設(shè)置成";"后就會(huì)輸出
1;2;3
4;5;6
(說(shuō)明:awk把分割后的第1、2、3個(gè)字段用$1,$2,$3...表示,$0表示整個(gè)記錄(一般就是一整行))
NF???? 當(dāng)前記錄中的字段個(gè)數(shù)
awk -F ':' '{print NF}' b的輸出為
3
3
表明b的每一行用分隔符":"分割后都3個(gè)字段
可以用NF來(lái)控制輸出符合要求的字段數(shù)的行,這樣可以處理掉一些異常的行
awk -F ':' '{if (NF == 3)print}' b
RS???? 輸入記錄分隔符,缺省為"\n"
缺省情況下,awk把一行看作一個(gè)記錄;如果設(shè)置了RS,那么awk按照RS來(lái)分割記錄
例如,如果文件c為
hello world; I want to go swimming tomorrow;hiahia
運(yùn)行 awk 'BEGIN{ RS = ";" } {print}' c 的結(jié)果為
hello world
I want to go swimming tomorrow
hiahia
合理的使用RS和FS可以使得awk處理更多模式的文檔,例如可以一次處理多行,例如文檔d為
1 2
3 4 5
6 7
8 9 10
11 12
hello
每個(gè)記錄使用空行分割,每個(gè)字段使用換行符分割,這樣的awk也很好寫(xiě)
awk 'BEGIN{ FS = "\n"; RS = ""} {print NF}' d 輸出
2
3
1
ORS:輸出記錄分隔符,缺省為換行符,控制每個(gè)print語(yǔ)句后的輸出符號(hào)
awk 'BEGIN{ FS = "\n"; RS = ""; ORS = ";"} {print NF}' d 輸出
2;3;1
(2)awk讀取shell中的變量
可以使用-v選項(xiàng)實(shí)現(xiàn)功能
$b=1
$cat f
apple
$awk -v var=$b '{print var, $var}' f
1 apple
shell調(diào)用awk實(shí)際上是fork一個(gè)子進(jìn)程出來(lái),而子進(jìn)程是無(wú)法向父進(jìn)程傳遞變量的,除非用重定向(包括管道)
a=$(awk '{print $b, '$b'}' f)
$echo $a
apple 1
其中,BEGIN和END中的語(yǔ)句分別在開(kāi)始讀取文件(in_file)之前和讀取完文件之后發(fā)揮作用,可以理解為初始化和掃尾。
awk中使用重定向
awk的輸出重定向類(lèi)似于shell的重定向。重定向的目標(biāo)文件名必須用雙引號(hào)引用起來(lái)。
$awk '$4 >=70 {print $1,$2 >"destfile" }' filename
$awk '$4 >=70 {print $1,$2 >>"destfile" }' filename
awk中使用管道
awk中的管道概念和shell的管道類(lèi)似,都是使用"|"符號(hào)。如果在awk程序中打開(kāi)了管道,必須先關(guān)閉該管道才能打開(kāi)另一個(gè)管道。也就是說(shuō)一次只能打開(kāi)一個(gè)管道。shell命令必須被雙引號(hào)引用起來(lái)?!叭绻蛩阍俅卧赼wk程序中使用某個(gè)文件或管道進(jìn)行讀寫(xiě),則可能要先關(guān)閉程序,因?yàn)槠渲械墓艿罆?huì)保持打開(kāi)狀態(tài)直至腳本運(yùn)行結(jié)束。注意,管道一旦被打開(kāi),就會(huì)保持打開(kāi)狀態(tài)直至awk退出。因此END塊中的語(yǔ)句也會(huì)收到管道的影響。(可以在END的第一行關(guān)閉管道)”
awk中使用管道有兩種語(yǔ)法,分別是:
awk output | shell input
shell output | awk input
對(duì)于awk output | shell input來(lái)說(shuō),shell接收awk的輸出,并進(jìn)行處理。需要注意的是,awk的output是先緩存在pipe中,等輸出完畢后再調(diào)用shell命令 處理,shell命令只處理一次,而且處理的時(shí)機(jī)是“awk程序結(jié)束時(shí),或者管道關(guān)閉時(shí)(需要顯式的關(guān)閉管道)”
$awk '/west/{count++} {printf "%s %s\t\t%-15s\n", $3,$4,$1 | "sort +1"} END{close "sort +1"; printf "The number of sales pers in the western"; printf "region is " count "." }' datafile (解釋?zhuān)?west/{count++}表示與“wes”t進(jìn)行匹配,若匹配,則count自增)
printf函數(shù)用于將輸出格式化并發(fā)送給管道。所有輸出集齊后,被一同發(fā)送給sort命令。必須用與打開(kāi)時(shí)完全相同的命令來(lái)關(guān)閉管道(sort +1),否則END塊中的語(yǔ)句將與前面的輸出一起被排序。此處的sort命令只執(zhí)行一次。
在shell output | awk input中awk的input只能是getline函數(shù)。shell執(zhí)行的結(jié)果緩存于pipe中,再傳送給awk處理,如果有多行數(shù)據(jù),awk的getline命令可能調(diào)用多次。
$awk 'BEGIN{ while(("ls" | getline d) > 0) print d}' f
輸出滿(mǎn)足某一條件的所有行的值
cat outest.txt | awk '$3<0.001 {print $1, $2 >>"test1.txt"}' >test2.txt
$n????????$1 the first parameter,$2 the second...
$#????????The?number?of?command-line?parameters.
$0????????The?name?of?current?program.
$?????????Last?command?or?function's?return?value.
$$????????The?program's?PID.
$!????????Last?program's?PID.
$@????????Save?all?the?parameters.
實(shí)例1:文件a,統(tǒng)計(jì)文件a的第一列中是浮點(diǎn)數(shù)的行的浮點(diǎn)數(shù)的平均值。
$cat a
1.021 33
1#.ll ? 44
2.53 6
ss ? ?7
awk 'BEGIN{total = 0;len = 0} {if($1~/^[0-9]+\.[0-9]*/){total += $1; len++}} END{print total/len}' a
說(shuō)明:$1~/^[0-9]+\.[0-9]*/表示$1與“/ /”里面的正則表達(dá)式進(jìn)行匹配,若匹配,則total加上$1,且len自增,即數(shù)目加1.“^[0-9]+\.[0-9]*”是個(gè)正則表達(dá)式,“^[0-9]”表示以數(shù)字開(kāi)頭,“\.”是轉(zhuǎn)義的意思,表示“.”為小數(shù)點(diǎn)的意思。“[0-9]*”表示0個(gè)或多個(gè)數(shù)字。
實(shí)例2:將d文件性別合并到c文件
$ cat c
zhangsan 100
lisi 200
wangwu 300
$ cat d
zhangsan man
lisi woman
方法1:$ awk ?'FNR==NR{a[FNR]=$0;next}{if($1 in a) print a[FNR],$2}' c d
實(shí)例3:找不同記錄(同上,取反)
$ awk 'FNR==NR{a[$0];next}!($0 in a)' a b
$ awk 'FNR==NR{a[$0]=1;next}!a[$0]' a b
$ awk 'ARGIND==1{a[$0]=1}ARGIND==2&&a[$0]!=1' a b
$ awk 'FILENAME=="a"{a[$0]=1}FILENAME=="b"&&a[$0]!=1' a b
7
8
方法2:$ sort a b |uniq -d
方法3:$ grep -vf a b
實(shí)例4:合并兩個(gè)文件
1)將d文件性別合并到c文件
方法1:$ awk ?'FNR==NR{a[$1]=$0;next}{print a[$1],$2}' c d
zhangsan 100 ?man
lisi 200 woman
wangwu 300 man
方法2:$ awk ?'FNR==NR{a[FNR]=$0}NR>FNR{print a[FNR],$2}' c d
說(shuō)明:NR==FNR匹配第一個(gè)文件,NR>FNR匹配第二個(gè)文件,將$1為數(shù)組下標(biāo)
方法3:$ awk 'ARGIND==1{a[FNR]=$0}ARGIND==2{print a[FNR],$2}' c d
2)將a.txt文件中服務(wù)名稱(chēng)合并到一個(gè)IP中
$ cat a.txt
192.168.2.100 : httpd
192.168.2.100 : tomcat
192.168.2.101 : httpd
192.168.2.101 : postfix
192.168.2.102 : mysqld
192.168.2.102 : httpd
$ awk -F: -vOFS=":" '{a[$1]=a[$1] $2}END{for(i in a)print i,a[i]}' a.txt
$ awk -F: -vOFS=":" '{a[$1]=$2 a[$1]}END{for(i in a)print i,a[i]}' a.txt
192.168.2.100 : httpd ?tomcat
192.168.2.101 : httpd ?postfix
192.168.2.102 : mysqld ?httpd
說(shuō)明:a[$1]=$2 第一列為下標(biāo),第二個(gè)列是元素,后面跟的a[$1]是通過(guò)第一列取a數(shù)組元素(服務(wù)名),結(jié)果是$1=$2 $2,并作為a數(shù)組元素。
3)將第一行附加給下面每行開(kāi)頭
$ cat a.txt
xiaoli
a 100
b 110
c 120
$ awk 'NF==1{a=$0;next}{print a,$0}' a.txt
$ awk 'NF==1{a=$0}NF!=1{print a,$0}' a.txt
xiaoli ?a 100
xiaoli ?b 110
xiaoli ?c 120
實(shí)例5:倒敘列打印文本
$ cat a.txt
xiaoli ? a 100
xiaoli ? b 110
xiaoli ? c 120
$ awk '{for(i=NF;i>=1;i--){printf "%s ",$i}print s}' a.txt
100 a xiaoli
110 b xiaoli
120 c xiaoli
$ awk '{for(i=NF;i>=1;i--)if(i==1)printf $i"\n";else printf $i" "}' a.txt
說(shuō)明:利用NF降序輸出,把最后一個(gè)域作為第一個(gè)輸出,然后自減,print s或print ""打印一個(gè)換行符
實(shí)例6:從第二列打印到最后
方法1:$ awk '{for(i=2;i<=nf;i++)if(i==nf)printf $i"\n";else printf $i" "}' a.txt< p>
方法2:$ awk '{$1=""}{print $0}' a.txt
a 100
b 110
c 120
實(shí)例7:將c文件中第一列放到到d文件中的第三列
$ cat c
a
b
c
$ cat d
1 one
2 two
3 three
方法1:$ awk 'FNR==NR{a[NR]=$0;next}{$3=a[FNR]}1' c d
說(shuō)明:以NR編號(hào)為下標(biāo),元素是每行,當(dāng)處理d文件時(shí)第三列等于獲取a數(shù)據(jù)FNR(重新計(jì)數(shù)1-3)編號(hào)作為下標(biāo)。
方法2:$ awk '{getline f<"c";print $0,f}' d< p>
1 one a
2 two b
3 three c
1)替換第二列
$ awk '{getline f<"c";gsub($2,f,$2)}1' d< p>
1 a
2 b
3 c
2)替換第二列的two
$ awk '{getline f<"c";gsub("two",f,$2)}1' d< p>
1 one
2 b
3 three
實(shí)例8:數(shù)字求和
方法1:$ seq 1 100 |awk '{sum+=$0}END{print sum}'
方法2:$ awk 'BEGIN{sum=0;i=1;while(i<=100){sum+=i;i++}print sum}'< p>
方法3:$ awk 'BEGIN{for(i=1;i<=100;i++)sum+=i}end{print sum}' dev null< p>
方法4:$ seq -s + 1 100 |bc
實(shí)例9:每隔三行添加一個(gè)換行符或內(nèi)容
方法1:$ awk '$0;NR%3==0{printf "\n"}' a
方法2:$ awk '{print NR%3?$0:$0"\n"}' a
方法3:$ sed '4~3s/^/\n/' a
實(shí)例10:字符串拆分
方法1:
$ echo "hello" |awk -F '' '{for(i=1;i<=nf;i++)print $i}'< p>
$ echo "hello" |awk -F '' '{i=1;while(i<=nf){print $i;i++}}'< p>
h
e
l
l
o
方法2:
$ echo "hello" |awk '{split($0,a,"''");for(i in a)print a[i]}' ?#無(wú)序
l
o
h
e
l
實(shí)例11:統(tǒng)計(jì)字符串中每個(gè)字母出現(xiàn)的次數(shù)
$ echo a,b.c.a,b.a |tr "[,. ]" "\n" |awk -F '' '{for(i=1;i<=nf;i++)a[$i]++}end{for(i in a)print i,a[i]|"sort -k2 -rn"}'< p>
a 3
b 2
c 1
實(shí)例12:第一列排序
$ awk '{a[NR]=$1}END{s=asort(a,b);for(i=1;i<=s;i++){print i,b[i]}}' a.txt< p>
說(shuō)明:以每行編號(hào)作為下標(biāo)值為$1,并將a數(shù)組值放到數(shù)組b,a下標(biāo)丟棄,并將asort默認(rèn)返回值(原a數(shù)組長(zhǎng)度)賦值給s,使用for循環(huán)小于s的行號(hào),從1開(kāi)始到數(shù)組長(zhǎng)度打印排序好的數(shù)組。
實(shí)例13:刪除重復(fù)行,順序不變
$ awk '!a[$0]++' file
實(shí)例14:刪除指定行
刪除第一行:
$ awk 'NR==1{next}{print $0}' file #$0可省略
$ awk 'NR!=1{print}' file
$ sed '1d' file
$ sed -n '1!p' file
實(shí)例15:在指定行前后加一行
在第二行前一行加txt:
$ awk 'NR==2{sub('/.*/',"txt\n&")}{print}' a.txt
$ sed'2s/.*/txt\n&/' a.txt
在第二行后一行加txt:
$ awk 'NR==2{sub('/.*/',"&\ntxt")}{print}' a.txt
$ sed'2s/.*/&\ntxt/' a.txt
實(shí)例16:通過(guò)IP獲取網(wǎng)卡名
$ ifconfig |awk -F'[: ]' '/^eth/{nic=$1}/192.168.18.15/{print nic}'
實(shí)例17:浮點(diǎn)數(shù)運(yùn)算(數(shù)字46保留小數(shù)點(diǎn))
$ awk 'BEGIN{print 46/100}'
$ awk 'BEGIN{printf "%.2f\n",46/100}'
$ echo 46|awk '{print $0/100}'
$ echo 'scale=2;46/100' |bc|sed 's/^/0/'
$ printf "%.2f\n" $(echo "scale=2;46/100" |bc)
結(jié)果:0.46
實(shí)例18:替換換行符為逗號(hào)
$ cat a.txt
1
2
3
替換后:1,2,3
方法1:
$ awk '{s=(s?s","$0:$0)}END{print s}' a.txt
說(shuō)明:三目運(yùn)算符(a?b:c),第一個(gè)s是變量,s?s","$0:$0,第一次處理1時(shí),s變量沒(méi)有賦值初值是0,0為假,結(jié)果打印1,第二次處理2時(shí),s值是1,為真,結(jié)果1,2。以此類(lèi)推,小括號(hào)可以不寫(xiě)。
方法2:
$ tr '\n' ',' < a.txt
實(shí)例19.統(tǒng)計(jì)第一列的數(shù)據(jù)分布
awk -F '\t' '{sum[$1]++}END{for(i in sum) print i "\t" sum[i]}' example.txt
補(bǔ)充::
可以將待篩選的用戶(hù)id存入一個(gè)文件userid.txt。一行一個(gè)id。過(guò)濾data.txt,找到userid.txt中的用戶(hù)id的數(shù)據(jù)來(lái)輸出。
awk -F '\t' 'BEGIN{while(getline<"userid.txt") a[$1]=1;} {if(a[$2]==1) print $0;}' data.txt > new_data.txt
BEGIN語(yǔ)法是在逐行解析之前執(zhí)行的一段代碼。這里它會(huì)加載userid.txt將用戶(hù)id存入關(guān)聯(lián)數(shù)組a中:key是用戶(hù)id,value是1。
后面的代碼塊開(kāi)始逐行解析,用data.txt的第二列做key去關(guān)聯(lián)數(shù)組a中查找。如果查找到value為1,就輸出整行。
Shell
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶(hù)投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶(hù)投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。