linux awk 3

awk的基本功能是對文件進行指定規則瀏覽和抽取信息。
基本格式:
(1) awk [-F 分隔域] 'command' input-file(s)
(2) 寫入shell腳本中
(3) awk -f awk-script-file input-file(s)

注意:這裏如果使用if等編程語句,要用{}括起來。


test

name    grade    score    id
hover    2        96        2003073
twq        3        91        2003074
zsm        4        92        2003075
hzm        5        95        2003076
bl        6        96        2003077


1,文本過濾處理:
(1) awk '{print $0}' test   #打印文件的全部內容
注意:這裏awk使用函數print用來打印整個文件的內容。其中的$0就表示整個文件的內容。

(2) awk '{print $1}' test   #抽取文件test中的第一列
注意:如果awk沒有使用-F指定分隔符號,默認的分隔符號是空格和TAB鍵。

#列出所有的用戶名和登陸的shell名
awk -F : '{print $1,$6}' /etc/passwd

(3) awk -F : '$1=="root" {print $0}' /etc/passwd
指打印用戶名爲root的那一行

2,文本格式定製
(1)給輸出信息加上表頭
awk -F : 'BEGIN {print "name        shell\n--------------------------------"}
    {print $!"\t"$6}' /etc/passwd

(2)
awk -F : 'BEGIN {print "name        shell\n--------------------------------"}
    {print $!"\t"$6} END {"end-of-report"}' /etc/passwd

3,在awk中使用正則表達式
^                表示匹配行首的字符
[...]            匹配[]正的任意一個字符
(str1|str2)        匹配含有str1或str2的行       
.                匹配任意一個字符


(1)匹配
爲使一域匹配一正則表達式,可以使用以下兩種方法:
    1)$n~正則表達式
    2)if($n~正則表示式) print $0

awk -F: '$0 ~ /^root/' /etc/passwd  #打印以root開頭的行
awk -F: '{if($0 ~ /^root/) print $0}' /etc/passwd  #和上一句等效

*精確匹配*
#打印名字爲root的用戶在/etc/passwd文件中的記錄
awk -F : '$1=="root" {print $0}' /etc/passwd
#打印路徑爲/root的用戶在/etc/passwd中的記錄
awk -F : '$6=="\/root" {print $0}' /etc/passwd

4,在awk中使用條件操作符
<    小於        >=    大於等於
<=    小於等於    ~    匹配正則表達式
==    等於        !~    不匹配正則表達式
!=    不等於

(1)模糊匹配
i)使用if         {if($1~/zhengxh/) print $0}
ii)不用if        '$0 ~ /zhengxh/'
ex:
    awk '$0~/zhengxh/' filename
    或awk '{if($0~/zhengxh/) print $0} filename    #輸出含有zhengxh的行
    或awk '/zhengxh/' filename

(2)精確匹配
$n=="chars"
    awk '$1=="zhengxh" {print $0}' filename        #輸出第一列等於zhengxh的行

(3)反向匹配
$n !~ /adf/
    awk '$1 !~ /zhengxh/ {print $0}' filename    #輸出第一列不是zhengxh的行

(4)大小寫匹配
    awk '/[zZ]hengxh/'  filename     #匹配含有zhengxh 或是Zhengxh的字符串
   
(5)使用或運算
    awk '$0 ~ /(zhengxh|hover)/' filename     #查找含有zhengxh或hover字串的行
    或awk '{if($0~/zhengxh/ OR $0~/hover/) print $0}' filename

(6)內置變量
ARGC    命令行參數個數
ARGV    命令行參數排列
ENVIRON    環境變量支持隊列的
FNR        瀏覽文件的記錄數
FS        設置輸入域分隔符,與-F同
NF        記錄域的個數
NR        已讀的記錄數
OFS        輸出域分隔符
ORS        輸出記錄分隔符
RS        控制記錄分隔符


awk 的具體運用(FAQ)
* 把一個文件中滿足條件的放到一個文件不滿足條件的放到另一個文件
awk -F: '{if(NF==6) print $0 > "yes" else print $0 > "no" }' filename


*如何在awk中使用變量
要注意的是在awk中的表達式一般是用''號括起來的,在shell中單引號是全屏蔽符,所以用單引號使得變量無法生效,在使用shell變量時,可以這樣使用

##########################

#/bin/sh
#

name="zhengxh"

count=`awk -F: '
    /'${name}'/{        #這裏需要使用變量的地方把變量隔開
        sum+=$3   
    }
   
    END { print sum }
'`

*使用awk輸出文件的倒數第N行
tail -n $N $filename | awk '{if(NR==1) print $0}'

*)如何在AWK中使用外部變量
1)aa="aaaaaaa"
awk '{print "'"${aa}"'"}' $filename
2)
以下使用外部變量時有錯:
#!/bin/bash
filepath=/etc/passwd
user=root
result=`awk -F":" '/$user/ { print $1}' $filepath`
echo $result
$
改正:
awk -F':' '/'"$user"'/{print $1}' $filepath





*如何把AWK中的值,傳送到外部的SHELL變量
使用$() 或 ``
aa=`awk -F: '{print $0}' $filename`

*進行統計
文件aa.txt
一個用戶可能有多個記錄,這時只統計一次:

數據          用戶ID        下載文件名稱   用戶所在地  等。。。。。
20071128,0001,1,null,600571021800,028 
20071128,0002,1,null,600571001800,021
20071128,0002,1,null,600571001802,021
20071128,0003,1,null,600571031800,020
20071128,0004,1,null,600571001800,010

統計各個的號碼(最後一個字段)數量
awk -F, '{if(!b[$2$6]){a[$6]++;b[$2$6]++}}END{for(i in a){print i,a[i]}}'

*如何把多個語句放在一句話(一行)中處理
cat "$file" | awk '{ip=$1; i=index($0,"\google"); if(i>1){ua = substr($0,i); print ip "\t" ua}}'

*把記錄
aa,bb,cc [name, address, age]
變成記錄
ip,aa,bb,cc [ip,name,address,age]

awk -F,    '{pirntf "\"192.168.5.154\","$0}'

*取一個字符串的首字母
str=abc
echo ${str:0:1}
echo $str|awk '{print substr($0,1,1)}'
echo $str|sed 's/\(.\).*/\1/'

*如何在一字符串的前面加上字符串 addtext
awk '{print "addtext \""$0"\""}' temp

*計算不重複的列的總和
aa|001|23
ac|001|23
bb|002|213
cc|004|32
dd|005|34

awk -F'|' '!a[$1]++{sum+=$3} END{print sum} ' filename

*定義多個分界符
aa cc dd
bb,ee ff

awk -F'[ ,]' '{print $3}' filename
 
有時候有可能出現多個分隔符號,但是我們需要把它當成一個,這時就要用:
***
#echo "adf::adf:f" | awk -F'[:]+' '{print $2}'
#adf
***
#echo "adf::adf:f" | awk -F':' '{print $2}'
#                            #輸出空
***

*如何用awk處理這樣的文件格式?
源文件格式:
  
表1313
                               客戶經理業績情況表(月報表)
支局所名稱:XXXX儲蓄所    月份:10     
客戶經理
業績(累計日積數)
酬金
姓名                  代號     活期               整整3月
整整6月               整整1年            整整2年                整整3年
整整5年             整整8年               零整1年             零整3年
零整5年              定活兩便        
蘭                  37040576  0.00                 0.00                 0.00
0.00                 0.00                 0.00                 0.00
0.00                 0.00                 0.00                 21340.00
0.00                 0.00                 
禚樹徵              37040585  27277.21             120.00               0.00
2965.22              0.00                 0.00                 0.00
0.00                 0.00                 0.00                 0.00
0.00                 845615151469035520.00
秦                  37040502  20094.30             0.00                 0.00
0.00                 0.00                 0.00                 0.00
0.00                 0.00                 0.00                 0.00
0.00                 622937933443235840.00
           合     計          444868.41            0.00                 0.00
2965.22              0.00                 0.00                 10764.20
0.00                 0.00                 0.00                 0.00
18600.00             13791245122257916000.00

如何用awk處理成以下格式(只要裏面的記錄並用逗號分割每個字段,最後一個字段不要,表頭和表尾不要):
"蘭",37040576,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,21340.00,0.00                 
"禚樹徵",37040585,27277.21,120.00,0.00,2965.22,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00
"秦",37040502,20094.30,0.00,0.00,0.00,0.00,0.00,,0.00,0.00,0.00,0.00,0.00,0.00

awk '{sub("[ \t]", ","); print $0}' temp
awk '{sub("[ ,\t]", ","); print $0}' temp

*如何用TAB做分隔符號
awk -F'\t'
awk -F'[ \t]'  #默認是這樣,以空格或TAB做分隔符
一般模式:awk -F'rexp' '{}' filename
這裏rexp是一個正則表達式,用來指示要使用的分隔符。


*--------------------------
在awk腳本中有下面一段

BEGIN{split("123#456#789",team,"#")}
END{for(i in team) print team}

預測的輸出應該是
123
456
789
啊!

爲什麼實際的輸出是
456
789
123
呢?

答:
---
while(++i in team) print team[i]

----------------------------

*-awk中使用system()
answer:
ls | awk '{if (system("ls " $0) == 0) {print "file " $0 " exists !"}}'


*-調用外部命令和awk結合
使用getline得到外部命令的輸入f
 ls | awk '{getline ll; print $ll}'

--------------------------
*-只輸出第一行的內容
awk '{print; exit}'

*-多shell命令
awk ’BEGIN{while("dir|sed 1,3!d"|getline)print $1}‘

*-在awk的輸出中加單引號
#cat file
rwxrwsrwx   gprs    512 GPRS

awk '{printf("%s %s '"'%s'"' %s\n",$1,$2,$3,$4)}' file
    在這裏要理解的是:上面的表達式分成了三塊,前面的''內的內容是一塊,中間的雙引號內的內容是一塊,最後的單引號裏的內容是一塊;由於單引號在雙引號中的作用被屏蔽,所以輸出的變量會帶上單引號。從而達到預定結果。

*-得到df -h 顯示出來的百分數字(去掉百分號)
(1)df -h | awk '{if(NR!=1) print $5}' | cut -d% -f 1
(2)df -h | awk -F'[ \t%]+' '{if(NR!=1) print $5}'


***
實現加和
中間結果如下所示:
CPU usr sys idl
0 13 4 76
1 9 4 79
要想顯示下列結果:
1 22 8 155
***
cat data | awk '{if(NR!=1) a+=$1;b+=$2;c+=$3} END{print a,b,c,d,e}'

***
如何實現以幾個字母中任意一個打頭的字符串的查找
cat data
Mike Harrington:(510) 548-1278:250:100:175
Christian Dobbins:(408) 538-2358:155:90:201
Susan Dalsass:(206) 654-6279:250:60:50
Archie McNichol:(206) 548-1348:250:100:175
Jody Savage:(206) 548-1278:15:188:150
Guy Quigley:(916) 343-6410:250:100:175
Dan Savage:(406) 298-7744:450:300:275
Nancy McNeil:(206) 548-1278:250:80:75
John Goldenrod:(916) 348-4278:250:100:175
Chet Main:(510) 548-5258:50:95:135
Tom Savage:(408) 926-3456:250:168:200
Elizabeth Stachelin:(916) 440-1763:175:75:300

awk -F'[ :]' '$1~/^[MJ] {print $1}'

輸出以D開頭的域
awk -F':' '{for(i=1;i<=NF;i++) if($i~/^D/) print $i}' data2



****每一行的和
統計
#cat ab
a 1
a 2
b 2

awk '{a[$1]+=$2} END{for(i in a) print i,a[i]}' file


-----------------------------------
*對兩個文件的處理
----------
大家好,想請教一個問題,我現在有兩個文件,如下所示,這兩個文件格式都是一樣的。我想首先把文件2的第五列刪除,然後用文件2的第一列減去文件一的第一列,把所得的結果對應的貼到原來第五列的位置,請問這個腳本該怎麼編寫?
file1:
50.481  64.634  40.573  1.00  0.00
51.877  65.004  40.226  1.00  0.00
52.258  64.681  39.113  1.00  0.00
52.418  65.846  40.925  1.00  0.00
49.515  65.641  40.554  1.00  0.00
49.802  66.666  40.358  1.00  0.00
48.176  65.344  40.766  1.00  0.00
47.428  66.127  40.732  1.00  0.00
51.087  62.165  40.940  1.00  0.00
52.289  62.334  40.897  1.00  0.00
file2:
48.420  62.001  41.252  1.00  0.00
45.555  61.598  41.361  1.00  0.00
45.815  61.402  40.325  1.00  0.00
44.873  60.641  42.111  1.00  0.00
44.617  59.688  41.648  1.00  0.00
44.500  60.911  43.433  1.00  0.00
43.691  59.887  44.228  1.00  0.00
43.980  58.629  43.859  1.00  0.00
42.372  60.069  44.032  1.00  0.00
43.914  59.977  45.551  1.00  0.00

--答--
awk 'NR==FNR{a[NR]=$1}NR!=FNR{$5=a[FNR]-$1;print}' file2 file1

說明:
當NR==FNR時,是第一個文件,到了第二個文件時FNR會從0開始計數,而NR卻繼續在原來的基礎上自增。
先把第一個文件中要使用的內容保存到一個數組中,然後在處理第二個文件時才使用。
這裏包含了很好的處理多個文件的方法,值得借鑑。
-------------------------------------------------


**
源文件如下:
37123456,123456789,601234020200051640,"孔霞","03",123456789,"2008/01/06",1,4000,5060.41
37123456,123456789,601234020200062521,"慄汝禮","03",123456010,"2008/01/06",1,100,110.91
37123456,123456789,601234020200069800,"柯純龍","03",370786017,"2008/01/06",1,20000,19500
37123456,123456789,601234020200069800,"柯純龍","03",123456030,"2008/01/06",1,31000,500
37123456,123456789,601234020200068018,"嚴鳳書","03",123456789,"2008/01/06",2,50000,100163.39
37123456,123456789,601234020200070039,"劉慶","03",123456789,"2008/01/06",2,4000,8000
37123456,123456789,601234020200060554,"王蘭英","03",123456789,"2008/01/06",1,1600,91.26
37123456,123456789,601234020200070039,"劉慶","03",123456789,"2008/01/06",2,4000,4000
37123456,123456789,601234020200067710,"羅有豔","03",123456789,"2008/01/06",2,3000,12012.01
37123456,123456789,601234020200064742,"孫祥婷","03",123456789,"2008/01/06",1,50,12.61
37123456,123456789,601234020200069800,"柯純龍","03",123456030,"2008/01/06",1,200,300
37123456,123456789,601234020200060554,"王蘭英","03",123456789,"2008/01/06",1,1000,1091.26
處理要求如下:
如果第三列中的數據是唯一的,就保留這一行,如果有重複的,就保留最後一個記錄行。

--------答---------
awk -F, '{a[$3]=$0}END{for( i in a)print a[i]}' urfile

------------------------------

*如何快速獲取特定字符串的前2(n)行和後2(n)行
$cat file

put 8
put 9
put 10
abc
put 11
put 12
put 13
put 14
abc
put 15
put 16
put 17
put 18
abc
put 19
put 20
put 21
put 22
put 23
abc
put 24
put 25
put 26
put 27
abc
put 28
put 29
put 30
put 31
put 32
abc
put 33
put 34
put 35
put 36
put 37

$ awk '{a[NR]=$0}/abc/{for(i=2;i>=0;i--) print a[NR-i];for(j=1;j<=2;j++){if(!getline) exit;print}print ""}' urfile
小結:
(1)這裏使用了數組的功能,數組在作爲緩存是普遍用法,要記住。
但這裏如果文件超大的話,緩衝區的負擔太大,應換存自己需要的哪些行(這裏我只換存了4行)
$ awk '{a[NR%4]=$0}/abc/{for(i=2;i>=0;i--) print a[(NR-i)%4];for(j=1;j<=2;j++){if(!getline) exit;print}print ""}' urfile
(2)使用了getline函數-- $ man awk  就知道,getline函數的作用是: 1)讀取下一行2)set $0
注意這兩個元素的應用.



*)如何提取aaaa12123adsf adfadfbbbb 的aaaa和bbbb中間的內容
$cat file
adfaaaaadfadfadfdfadabbbb
adfaaaaadf  ad323452 adfadfdfadabbbbz
$
1)sed -e 's/.*\(aaaa\)\(.*\)\(bbbb\).*/\2/g' file
2)sed -e 's/.*\(a\{3\}\)\(.*\)\(b\{3\}\).*/\2/g' file
3)echo "aaaa121312dfadfbbbbb" | awk -F'aaaa|bbbb' '{print $2}'

*)我以如下字符要處理

a  123
b  124
c   125
a   126
d   127
e   128
ac  129

如果第一列出現兩次或兩次以上將其打印出來,並計算出現次數。
$ awk '{a[$1]++;} END{for(i in a) if(a[i]>=2) {print i,a[i]}}' file
分析: 由以上的命令可以得到流程:
a["a"] 2
a["b"] 1
a["c"] 1
a["d"] 1
a["e"] 1
a["ac"] 1
而for(i in a)  則是要遍歷的i的值是:a,b,c,d,e,ac



*)去掉重複的行
awk '!a[$0]++' file

*)去掉重複行,並保持順序不變
awk 'f[$0]!=1{print;f[$0]=1}'

*)打印重複行
1)awk '{a[$0]++} END{for(i in a) {if(a[i]>1){print i}}}' filename
2)sort cc  | uniq -dc

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