awk工具使用

awk 參數:
ARGC    命令行參數的個數
ARGV:  命令行參數數組
ARGIND 當前被處理文件的ARGV標誌符
NR 已經讀出的記錄數
FNR   當前文件的記錄數
FS 輸入字段分隔符(缺省爲:space:),相當於-F選項
OFS輸出字段分隔符(缺省爲:space:)
NF:當前記錄中的字段個數
RS:輸入記錄分隔符,缺省爲"\n"
ORS:輸出記錄分隔符,缺省爲換行符,控制每個print語句後的輸出符號
awk讀取shell中的變量:可以使用-v選項實現功能
FIELDWIDTHSL:設置輸入字段寬度的空白分隔字符串(如下面的時間格式轉換)
echo "20120905"|awk 'BEGIN{FIELDWIDTHS="4 2 2";OFS="-"}{print $1,$2,$3} '
$1=$1可以使OFS生效,$0=$0可以使FS生效(注意FS設置可以再BEGIN設置)。
[root@node1 ~]# echo '1 1 1                                                                   
2 2 2' |awk 'NR==1{OFS=":";$1=$1;print}NR==2{OFS="#";$1=$1;print}'
1:1:1
2#2#2
[root@node1 ~]# echo '1 1 1
2 2 2' |awk 'NR==1{OFS=":";print}NR==2{OFS="#";$1=$1;print}'
1 1 1
2#2#2
[root@node1 ~]# echo '1 1 1                                                                  
2 2 2' |awk 'NR==1{OFS=":";$1=$1;print}NR==2{OFS="#";$1=$1;print}'
1:1:1
2#2#2
[root@node1 ~]# echo '1:1:1
2#2#2' |awk 'NR==1{FS=":";$0=$0;print $1}NR==2{FS="#";$0=$0;print $1}'
1
2
[root@node1 ~]# echo '1:1:1
2#2#2' |awk 'NR==1{FS=":";print $1}NR==2{FS="#";$0=$0;print $1}'
1:1:1
2
awk正則
\Y 匹配一個單詞開頭或者末尾的空字符串。
\B 匹配單詞內的空字符串。
\< 匹配一個單詞的開頭的空字符串,錨定開始。
\> 匹配一個單詞的末尾的空字符串,錨定末尾。
\w 匹配一個字母數字組成的單詞。
\W 匹配一個非字母數字組成的單詞。
\‘ 匹配字符串開頭的一個空字符串。
\' 匹配字符串末尾的一個空字符串。
awk 數組
awk的數組,一種關聯數組(Associative Arrays),下標可以是數字和字符串。因無需對數組名和元素提前聲明,也無需指定元素個數 。
多維數組,array[index1,index2,……]:SUBSEP是數組下標分割符,默認爲“:”。可以事先設定SUBSEP,也可以直接在SUBSEP的位置輸入你要用的分隔符
提起AWK數組,下面一個用的類型,很常見:
awk 'NF{a[$1]=a[$1]" "$2;next}END{for(i in a)print i,a[i]}'  filename
有時候可能是下面那樣,其實效果一樣
awk '{a[$1]=a[$1]" "$2}END{for(i in a)print i,a[i]}' filename
NF{...}這段表示非空白行,然後以$1作爲數組a的下標,把$2的值賦值給a[$1],然後用END{}這段實行打印出來。

awk函數:
算術函數:
略了吧!很少用。
字符串處理函數:
sub(r,s)  在整個$0中用s替代第一次出現的r,如果成功則返回1,否則返回0,如沒有給出t則默認爲$0
gsub(r,s) 在整個$0中用s替代r
index(s,t) 返回字符串s中字符串t的第一位置,如果沒有字符串t則返回0
length(s) 返回字符串s長度,如果沒有給s則返回$0長度
blength (s) 返回字符串s長度(以字節爲單位)。如果未給出s參數,則返回整個記錄的長度($0 記錄變量)。
match(s,r) 如果正則r在s中出現,則返回出現的起始位置,如果沒有出現則返回爲0,並設置RESTART和RLENGTH值
split(s,a,sep) 使用字段分隔符sep將字符串s分解到數組a的元素中,返回元素個數。如果沒有給出sep,則使用FS.數組分隔符和字段分隔採用相同的方式。
sprint(fmt,exp) 返回經fmt格式化後的exp
substr(s,p,n)  返回字符串s中從位置p開始的最大長度爲n的子串。如果沒有給出n,返回從p開始剩餘字符串。
tolower(s) 將字符串s中的大寫字符都轉換成小寫,並返回新串。
toupper(s) 將字符串s中的小寫字符都轉換成大寫,並返回新串。
getline函數:getline函數可以從當前文件,從另一文件,從shell中讀取,從管道讀取。
getline函數得到下一行當沒有改變腳本的控制,可能返回的值爲:
1 如果能夠讀取一行
0 如果到了文件末尾
-1 如果遇到錯誤
[root@node1 ~]# awk 'BEGIN {printf "enter you name: ";getline name < "-";print name}'
enter you name: gaby
gaby
[root@node1 ~]# awk 'BEGIN {"who am i" | getline;name=$1;FS=":"}name ~ $1{print $NF}' /etc/passwd
/bin/bash
# awk 'BEGIN{while(getline < "/etc/passwd"){print$0;};close("/etc/passwd");}'
system函數
 
 
eg1:
cat 1.txt
a b c a d a
s d d d x s a
h j s a s h j h
j d f j a s j k j
要求:刪除行內與第一列字符重複的字符,達到這個結果:
a b c d
s d d d x a
h j s a s j
j d f a s k
awk '{a=$1;gsub( a,"");print a$0}' 1.txt  |column -t
a  b  c  d
s  d  d  d  x  a
h  j  s  a  s  j
j  d  f  a  s  k
awk '{a=$1;gsub(" ?"a,"");print a$0}' 1.txt
a b c d
s d d d x a
h j s a s j
j d f a s k
第二種在雙引號中使用了動態正則
printf()函數是格式化輸出函數, 一般用於向標準輸出設備按規定格式輸出信息。 其中格式化字符串包括兩部分內容: 一部分是正常字符, 這些字符將按原樣輸出; 另一部分是格式化規定字符, 以"%"開始, 後跟一個或幾個規定字符,用來確定輸出內容格式。
參量表是需要輸出的一系列參數, 其個數必須與格式化字符串所說明的輸出參數個數一樣多, 各參數之間用","分開, 且順序一一對應, 否則將會出現意想不到的錯誤。
(1). 可以在"%"和字母之間插進數字表示最大場寬。
例如: %3d 表示輸出3位整型數, 不夠3位右對齊。
%9.2f 表示輸出場寬爲9的浮點數, 其中小數位爲2, 整數位爲6,小數點佔一位, 不夠9位右對齊。
%8s 表示輸出8個字符的字符串, 不夠8個字符右對齊。
如果字符串的長度、或整型數位數超過說明的場寬, 將按其實際長度輸出.但對浮點數, 若整數部分位數超過了說明的整數位寬度, 將按實際整數位輸出;若小數部分位數超過了說明的小數位寬度, 則按說明的寬度以四捨五入輸出.另外, 若想在輸出值前加一些0, 就應在場寬項前加個0。
[root@node1 ~]# echo "1.5" | awk '{printf ("%f\n",$1)}'
1.500000
[root@node1 ~]# echo "1.5" | awk '{printf ("%.0f\n",$1)}'
2
[root@node1 ~]# echo "1.5" | awk '{printf ("%.1f\n",$1)}'
1.5
[root@node1 ~]# echo "1.5" | awk '{printf ("%2.f\n",$1)}'
 2
[root@node1 ~]# echo "1.5" | awk '{printf ("%2.1f\n",$1)}'
1.5
[root@node1 ~]# echo "1.5" | awk '{printf ("%2.1f",$1)}'
1.5[root@node1 ~]# echo "1.5" | awk '{printf ("%.f",$1)}' 
(2). 可以在"%"和字母之間加小寫字母l, 表示輸出的是長型數。
例如: %ld 表示輸出long整數
(3). 可以控制輸出左對齊或右對齊, 即在"%"和字母之間加入一個"-" 號可說明輸出爲左對齊, 否則爲右對齊。
例如: %-7d 表示輸出7位整數左對齊
%d 十進制有符號整數 
%u 十進制無符號整數 
%f 浮點數 
%s 字符串 
%c 單個字符 
%p 指針的值 
%e 指數形式的浮點數 
%x %X 無符號以十六進制表示的整數 
%o 無符號以八進制表示的整數 
%g 自動選擇合適的表示法 
\n 換行
\f 清屏並換頁
\r 回車
\t Tab符
\xhh 表示一個ASCII碼用16進表示,其中hh是1到2個16進制數
eg1:找出系統中用戶名大於五個字符的用戶名稱:
# awk -F ":" '$1~/^....$/{print $1}' /etc/passwd
# awk -F ":" 'length($1)>4{print $1}' /etc/passwd
eg2:
[root@node1 ~]# cat  1.txt
uid:quota_used_rate
chenmeng:35%
wangfurong:20%
luoxuan:40%
guofeifei:20%
lihui:70%
wangwei:66%
wuhuixiong:44%
shashijie:22%
[root@node1 ~]# cat 2.txt
d:quota_used
wuhuixiong:100m
guofeifei:500m
luoxuan:200m
wangfurong:99m
shashijie:250m
chenmeng:150m
lihui:88m
wangwei:34m
要求寫腳本實現如下效果
chenmeng:35%:150m
# awk -F: 'NR==FNR{a[$1]=$NF;next};!/uid/{print $0":"a[$1]}'  2.txt 1.txt
# cat 1.txt |sort >a1;cat 2.txt |sort >b1;join -t ':' a1 b1
這個問題,我也是在網上遇到的,對應第一種方法,重點在於理解NR==FNR{a[$1]=$NF;next}這句,在awk裏面輸入文件是多個時,NR==FNR纔有意義,如果這個值爲true,表示還在處理第一個文件。因此這句話的意思就在文件2.txt中生成以用戶名爲下標的以$NF值爲結果的數組a。然後處理文件1.txt,打印出$0和名字對應下標的數組a的值。
第二種情況主要是使用了sort默認排序和join(找出兩個文件中,指定欄位內容相同的行,並加以合併,再輸出到標準輸出設備,注意兩個文件內容的排序)的文件合併。
eg3:
[root@node1 ~]# netstat -ant | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
ESTABLISHED   2
LISTEN   17
 access.log POST與GET統計
# cat /www/logs/access.log | egrep -o 'GET|POST' | awk '{++method[$NF]} END {for(num in method) print num, method[num]}'
POST 422
GET 18857
eg4
刪除文件中所有列都重複的記錄
#awk '! a[$0]++' 1.txt
eg5
文件a
220 34 50 70
553 556 32 21
1 1 14 98 33
文件b
10
8
2
要求文件a的每行數據與文件b的相對應的行的值相減,得到其絕對值。
awk '{getline j<"b";for(i=1;i<=NF;i++){$i>j?$i=$i-j:$i=j-$i}}1' a|column -t
210 24  40  60
545 548 24  13
1   1   12  96  31
eg6
文件a
aaa
bbb
ccc
ddd
文件b
111 xxx
222 xxx
333 xxx
444 xxx
要求文件a裏的數據依次替換文件b中的xxx字樣。
awk '{getline i<"a"}/xxx/{sub("xxx",i,$2)}1' b
111 aaa
222 bbb
333 ccc
444 ddd

####收集各類型網卡###
ifconfig -a |awk -F '[ ]' '{printf $1" "}END{print ""}'
ifconfig -a |grep -Po ".*(?= Link)"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章