該文本僅指awk的GNU實現稱為gawk Witch是最常用的,並帶有任何現代的Linux / Unix發行版。
[GNU AWK用戶指南] [Gnu-awk]是其參考,對於我使用的示例我使用了現實世界中的案例,主要是從我的[stackoverflow] [so]答案中。
Awk是一種類似於Perl的語言,僅更優雅。
- 阿諾德·羅賓斯(Arnold Robbins)
Awk是一種用於文本處理的編程語言,通常用作數據提取和報告工具。它是大多數類似Unix的操作系統的標準功能。
awk獎勵名稱...它的名字來自其作者的姓氏 - Alfred A Ho,Peter W Einberger和Brian K Ernighan。
awk ...搜索包含文件或標準輸入中某些模式的行。
主要用於數據提取和報告,例如總結其他公用事業程序的輸出中的信息。
C-like語法。
數據驅動:它描述了您要使用的數據,然後在找到該數據時要採取什麼措施。
pattern { action }
pattern { action }如果程序簡短:
awk ' program ' input-file1 input-file2注意:當心外殼引用問題1 。
cmd | awk ' program '注意: pipe將左側命令( cmd )的輸出重定向到awk命令2的輸入。
當代碼長時間時,將其放入文件中並以這樣的命令運行它通常更方便:
awk -f program-file input-file1 input-file2
cmd | awk -f program-file或者只是像shebang一樣使其可執行:
#! /bin/awk -f
BEGIN { print " hello world!! " }-F fs將FS變量設置為fs 。
-v var=val在執行程序開始之前,將變量var設置為值val 。
注意:它可以多次使用,每次設置另一個變量。
這些特殊的模式或阻止為awk程序提供啟動和清理操作。
BEGIN{
// initialize variables
}
{
/pattern/ { action }
}
END{
// cleanup
}BEGIN ,在消耗所有輸入後END 。
$ echo " hello " | awk ' BEGIN{print "BEGIN";f=1}
{print $f}
END{print "END"} '
BEGIN
hello
ENDawk ,為什麼要grepping ? $ cat lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ grep dolor lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.$ awk ' /dolor/ ' lorem_ipsum.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.注意:如果沒有給出操作,則默認操作是打印與給定模式匹配的記錄。
但是...我們如何找到每行的第一個和最後一句話?
當然, grep可以,但需要兩個步驟:
$ grep -Eo ' ^[^ ]+ ' lorem_ipsum.dat
Lorem
Maecenas
Nunc
Curabitur
Lorem
Aliquam$ grep -Eo ' [^ ]+$ ' lorem_ipsum.dat
elit.
condimentum.
ex.
tellus.
elit.
ultrices.讓我們在這裡看到awk :
$ awk ' {print $1,$NF} ' lorem_ipsum.dat
Lorem elit.
Maecenas condimentum.
Nunc ex.
Curabitur tellus.
Lorem elit.
Aliquam ultrices. awk將程序的輸入分為記錄和字段。
記錄由稱為記錄分離器RS的字符分開。默認情況下,記錄分離器是Unix Newline字符n 。
這就是為什麼默認情況下記錄是單行的原因。
此外, awk具有ORS輸出記錄分隔符,以控制stdout的方式。
RS和ORS應包含在引號中,這表明字符串常數。
要使用不同的字符或正則態度,只需將其分配給RS或 /和ORS變量:
BEGIN執行開始時,以便使用適當的分離器讀取第一個記錄。示例:
$ awk ' BEGIN{RS=" *, *";ORS="<<<---n"}
{print $0} ' lorem_ipsum.dat
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci <<< ---
euismod id nisi eget <<< ---
interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat <<< ---
et facilisis neque ultrices.
<<< --- $ awk ' {print $0} ' RS= " *, * " ORS= " <<<---n " lorem_ipsum.dat
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci <<< ---
euismod id nisi eget <<< ---
interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet <<< ---
consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat <<< ---
et facilisis neque ultrices.
<<< --- awk記錄會自動解析或分為稱為字段的塊。
默認情況下,字段由whitespace (一個或多個空格,選項卡或新線的任何字符串)分開,例如一行中的單詞。
要參考awk程序中的字段,您使用$標誌,然後使用所需的字段數。
因此, $1是指第一個字段,第二個領域為$2 ,依此類推。
重要: $0代表整個輸入記錄。
$ awk ' {print $3} ' lorem_ipsum.dat
dolor
erat
orci,
dapibus
dolor
mauris NF是一個預定義的變量,其值是當前記錄中的字段數。因此, $NF將永遠是記錄的最後一個字段。
$ awk ' {print NF} ' lorem_ipsum.dat
8
7
10
4
8
10VS.
$ awk ' {print $NF} ' lorem_ipsum.dat
elit.
condimentum.
ex.
tellus.
elit.
facilisis. FS保留了字段分離器的值,該值是單字符串或regex ,與輸入記錄中字段之間的分離匹配。
默認值為" " ,一個由單個空間組成的字符串。作為一個特殊的例外,此值意味著空間,選項卡和/或新線的任何序列都是單個分離器。
以與ORS相同的方式,我們有一個OFS變量來管理如何將字段發送到輸出流。
$ cat /etc/group
nobody: * :-2:
nogroup: * :-1:
wheel: * :0:root
daemon: * :1:root
kmem: * :2:root
sys: * :3:root
tty: * :4:root$ awk ' !/^(_|#)/&&$1=$1 ' FS= " : " OFS= " <-> " /etc/group
nobody < - > * < - > - 2< - >
nogroup < - > * < - > - 1< - >
wheel < - > * < - > 0 < - > root
daemon < - > * < - > 1 < - > root
kmem < - > * < - > 2 < - > root
sys < - > * < - > 3 < - > root
tty < - > * < - > 4 < - > root注意:嗯... $1=$1 ???? 3
牢記記錄和字段,現在準備了解我們以前的代碼:
$ awk ' {print $1,$NF} ' lorem_ipsum.dat
Lorem elit.
Maecenas condimentum.
Nunc ex.
Curabitur tellus.
Lorem elit.
Aliquam ultrices.這是兩個有用的內置變量:
NR :自程序執行開始以來, awk輸入記錄數量已經處理過。
FNR :當前文件中的當前記錄號, awk每次啟動新輸入文件時,將FNR重置為零。
$ cat n1.dat
one
two$ cat n2.dat
three
four$ awk ' {print NR,FNR,$0} ' n1.dat n2.dat
1 1 one
2 2 two
3 1 three
4 2 four格式字符串與ISO c中的字符串非常相似。
句法:
printf format, item1, item2, …
$ awk ' {printf "%20s <-> %sn",$1,$NF} ' lorem_ipsum.dat
Lorem < - > elit.
Maecenas < - > condimentum.
Nunc < - > ex.
Curabitur < - > tellus.
Lorem < - > elit.
Aliquam < - > ultrices.默認情況下, print和printf的輸出直接針對標準輸出,但我們可以使用重定向來更改目的地。
awk中的重定向是像殼命令中的重定向一樣書寫的,只是它們是在awk程序中寫的。
$ awk ' BEGIN{print "hello">"hello.dat"} ' $ awk ' BEGIN{print "world!">>"hello.dat"} ' $ cat hello.dat
hello
world !也可以通過管道將輸出發送到另一個程序:
$ awk ' BEGIN{sh="/bin/sh";print "date"|sh;close(sh)} '
dom nov 13 18:36:25 CET 2016 [流]可以指向stdin , stdout和stderr 。
例如,我們可以像這樣寫一條錯誤stderr :
$ awk ' BEGIN{print "Serious error detected!" > "/dev/stderr"} '
Serious error detected ! 在尷尬中,陣列是關聯的,每個數組是對,索引-值的集合,其中任何數字或字符串都可以是索引。
不需要聲明;可以隨時添加新對。
| 指數 | 價值 |
|---|---|
| “ perro” | “狗” |
| “ Gato” | “貓” |
| “ uno” | “一” |
| 1 | “一” |
| 2 | “二” |
引用數組:
array[index-expression]
分配值:
array[index-expression] = value
檢查鍵是否索引:
indx in array
迭代它:
for (var in array) {
var, array[var]
}使用數字值作為索引並保留順序:
for (i = 1 ; i < = max_index ; i++) {
print array[i]
}一個完整的示例:
$ cat dict.dat
uno one
dos two
tres three
cuatro fourawk ' {dict[$1]=$2}
END{if ("uno" in dict)
print "Yes we have uno in dict!"
if (!("cinco" in dict))
print "No , cinco is not in dict!"
for (esp in dict){
print esp, "->" ,dict[esp]
}
} ' dict.dat給你:
Yes we have uno in dict !
No , cinco is not in dict !
uno - > one
dos - > two
tres - > three
cuatro - > four gawk默認情況下不會對數組進行排序:
awk ' BEGIN{
a[4]="four"
a[1]="one"
a[3]="three"
a[2]="two"
a[0]="zero"
exit
}
END{for (idx in a){
print idx, a[idx]
}
} ' 4 four
0 zero
1 one
2 two
3 three但是您可以利用[Procinfo]進行分類:
awk ' BEGIN{
PROCINFO["sorted_in"] = "@ind_num_asc"
a[4]="four"
a[1]="one"
a[3]="three"
a[2]="two"
a[0]="zero"
exit
}
END{for (idx in a){
print idx, a[idx]
}
} ' 0 zero
1 one
2 two
3 three
4 fourgensub(regexp, replacement, how [, target]) :是替換字符串的最高級功能。
以及他們更簡單的選擇:
gsub(regexp, replacement [, target])
sub(regexp, replacement [, target])
擁有此文件:
$ cat lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.我們將交換每個逗號的左側和右側的單詞的位置。
$ awk ' {print gensub(/([^ ]+)( *, *)([^ ]+)/,
"\3\2\1", "g")} ' lorem.dat
Lorem ipsum dolor sit consectetur, amet adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim euismod, orci id nisi interdum, eget cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit consectetur, amet adipiscing elit.
Aliquam interdum mauris volutpat nisl et, placerat facilisis.使用gensub ,我們捕獲三組,然後交換順序。
為了說明一個更簡單的動作,讓我們更改逗號的點:
awk ' $0=gensub(/./, ",", "g") ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Maecenas pellentesque erat vel tortor consectetur condimentum,
Nunc enim orci, euismod id nisi eget, interdum cursus ex,
Curabitur a dapibus tellus,
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Aliquam interdum mauris volutpat nisl placerat, et facilisis,使用gsub替代方案:
awk ' gsub(/./, ",") ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Maecenas pellentesque erat vel tortor consectetur condimentum,
Nunc enim orci, euismod id nisi eget, interdum cursus ex,
Curabitur a dapibus tellus,
Lorem ipsum dolor sit amet, consectetur adipiscing elit,
Aliquam interdum mauris volutpat nisl placerat, et facilisis,當不需要小組捕獲時,此選項似乎更好。
其他有趣的功能是index和substr 。
index(in, find)
substr(string, start [, length ])
這樣的工作:
$ awk ' BEGIN{t="hello-world";print index(t, "-")} '
6$ awk ' BEGIN{t="hello-world";print substr(t,index(t, "-")+1)} '
world split函數用於創建一個由字符串除非分隔符的字符串創建數組,它返回創建數組的元素數量。
split(string, array [, fieldsep [, seps ] ])
$ cat passwd
jd001:x:1032:666:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:666:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:668:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:668:Rosa Camacho:/home/rc005:/bin/rbash$ awk ' n=split($0, a, ":"){print n, a[n]} ' passwd
7 /bin/rbash
7 /bin/rbash
7 /bin/bash
7 /bin/rbash
7 /bin/rbash注意:這可以更簡單地完成:
$ awk ' {print NF,$NF} ' FS= ' : ' passwd
7 /bin/rbash
7 /bin/rbash
7 /bin/bash
7 /bin/rbash
7 /bin/rbash編寫自定義功能很簡單:
awk ' function test(m)
{
printf "This is a test func, parameter: %sn", m
}
BEGIN{test("param")} '給我們:
This is a test func, parameter: param我們還可以使用return語句回饋表達式:
awk ' function test(m)
{
return sprintf("This is a test func, parameter: %s", m)
}
BEGIN{print test("param")} '通過參數解析是在函數內部製作局部變量的唯一方法。
標量值按值和數組通過引用傳遞,因此對函數內部數組進行的任何更改都將反映在全局範圍中:
awk ' function test(m)
{
m[0] = "new"
}
BEGIN{m[0]=1
test(m)
exit
}
END{print m[0]} '輸出:
new我們的挑戰:
01。記錄的倒數第二個單詞。
02。替換記錄。
03。將半隆放在每個記錄的末尾。
04。在每個單詞之間放置一個逗號。
05。一起嗎?
06。將奇數記錄重定向到文件,甚至將其重定向到另一個文件。
07。給定一個密碼文件獲取缺失字段。
08。字段交換。
09。示威者黑客。
10。我的孩子在哪裡?
11。數據聚合。
12。兩種模式之間的記錄。
13。場變換。
14。記錄到列。
15。 fasta文件處理。
16。複雜報告。
17。文件木器。
18。 Passwd和Group。
19。用戶連接。
20。正常運行時間總負載平均值。
擁有此源文件:
$ cat lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ awk ' {print $(NF-1)} ' lorem.dat
adipiscing
consectetur
cursus
dapibus
adipiscing
neque在這裡解釋不多, NF存儲了當前記錄中的字段數,因此NF-1點在最後一個和$(NF-1)之前將是其值。
我們的任務,文件記錄替換,第三行必須成為:
This not latin
沒什麼簡單的,只需圍繞NR (記錄數)。
代碼:
$ awk ' NR==3{print "This is not latin";next}{print} ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
This is not latin
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.避免next語句的替代解決方案:將新行分配給完整的記錄$0 。
例子:
$ awk ' NR==3{$0="This is not latin"}1 ' lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas pellentesque erat vel tortor consectetur condimentum.
This is not latin
Curabitur a dapibus tellus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aliquam interdum mauris volutpat nisl placerat, et facilisis.$ awk ' 1 ' ORS= " ;n " lorem.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit. ;
Maecenas pellentesque erat vel tortor consectetur condimentum. ;
Nunc enim orci, euismod id nisi eget, interdum cursus ex. ;
Curabitur a dapibus tellus. ;
Lorem ipsum dolor sit amet, consectetur adipiscing elit. ;
Aliquam interdum mauris volutpat nisl placerat, et facilisis neque ultrices. ;由於默認RS是Unix Break Line n因此我們只需要將半隆前綴與輸出記錄分離OFS的前綴前綴。
1呢? 4
$ awk ' {$1=$1}1 ' OFS= ' , ' lorem.dat
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit.
Maecenas,pellentesque,erat,vel,tortor,consectetur,condimentum.
Nunc,enim,orci,,euismod,id,nisi,eget,,interdum,cursus,ex.
Curabitur,a,dapibus,tellus.
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit.
Aliquam,interdum,mauris,volutpat,nisl,placerat,,et,facilisis,neque,ultrices.該代碼中最重要的部分是它如何迫使OFS的當前價值以$1=$1迫使記錄重建。
$ awk ' {$1=$1}1 ' OFS= ' , ' ORS= ' ;n ' lorem.dat
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit. ;
Maecenas,pellentesque,erat,vel,tortor,consectetur,condimentum. ;
Nunc,enim,orci,,euismod,id,nisi,eget,,interdum,cursus,ex. ;
Curabitur,a,dapibus,tellus. ;
Lorem,ipsum,dolor,sit,amet,,consectetur,adipiscing,elit. ;
Aliquam,interdum,mauris,volutpat,nisl,placerat,,et,facilisis,neque,ultrices. ;就像玩輸出vars: OFS和ORS一樣。
讓我們從最終解決方案開始:
$ awk ' NR%2{print > "even.dat";next}
{print > "odd.dat"} ' lorem.dat$ cat even.dat
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc enim orci, euismod id nisi eget, interdum cursus ex.
Lorem ipsum dolor sit amet, consectetur adipiscing elit$ cat odd.dat
Maecenas pellentesque erat vel tortor consectetur condimentum.
Curabitur a dapibus tellus.
Aliquam interdum mauris volutpat nisl placerat, et facilisis. [modulo]函數( % )在當前記錄號NR除以兩個:
$ awk ' {print NR%2} ' lorem.dat
1
0
1
0
1
0就我們現在而言,在awk 1中是真實的,為0 false 。我們重定向輸出評估這一事實。
next需要特別注意,它迫使awk立即停止當前的記錄過程並傳遞到下一個。
這樣,我們避開了一個看起來像這樣的雙重條件:
awk ' NR % 2{print > "even.dat"}
!NR % 2{print > "odd.dat"} ' lorem.dat$ cat /etc/passwd
jd001:x:1032:666:Javier Diaz::/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez::/bin/rbash
jp003:x:1000:666:Jose Perez::/bin/bash
ms004:x:8051:668:Maria Saenz::/bin/rbash
rc005:x:6550:668:Rosa Camacho::/bin/rbash讓我們通過將固定字符串"/home/"用戶名之前的連接前綴到主目錄中:
$ awk ' $6="/home/"$1 ' FS= ' : ' OFS= ' : ' /etc/passwd
jd001:x:1032:666:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:668:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:666:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:668:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:668:Rosa Camacho:/home/rc005:/bin/rbash我們的第一步應該考慮輸入和輸出的場分離器,結腸。
然後,我們需要找到void場位置,為此示例6 。
最後,我們使用給定的字符串和存儲在第一個字段中的用戶登錄名組成所需值。
print ,因為$6分配返回值將始終是真實的,而awk默認操作是打印受影響的記錄。
我們的目標:最後一個領域應該成為第一個,並首先成為最後的領域。
最終代碼:
$ awk -F : ' {last=$1;$1=$NF;$NF=last}1 ' FS= " : " OFS= ' : ' /etc/passwd
/bin/rbash:x:1032:666:Javier Diaz:/home/jd001:jd001
/bin/rbash:x:8050:668:Alejandro Gonzalez:/home/ag002:ag002
/bin/bash:x:1000:666:Jose Perez:/home/jp003:jp003
/bin/rbash:x:8051:668:Maria Saenz:/home/ms004:ms004
/bin/rbash:x:6550:668:Rosa Camacho:/home/rc005:rc005我們正在使用用於存儲第一個字段值的中間變量,我們將其值與最後一個值交換,最後我們將last變量分配給$NF ( $NF=last )。
有此輸出:
$ traceroute -q 1 google.com 2> /dev/null
1 hitronhub.home (192.168.1.1) 5.578 ms
2 217.217.0.1.dyn.user.ono.com (217.217.0.1) 9.732 ms
3 10.127.54.181 (10.127.54.181) 10.198 ms
4 62.42.228.62.static.user.ono.com (62.42.228.62) 35.519 ms
5 72.14.235.20 (72.14.235.20) 26.003 ms
6 216.239.50.133 (216.239.50.133) 25.678 ms
7 mad01s24-in-f14.1e100.net (216.58.211.238) 25.019 ms我們需要計算包裝的總時間。
$ traceroute -q 1 google.com 2> /dev/null |
awk ' {total+=$(NF-1)}
END{print "Total ms: "total} '
Total ms: 153.424由於未指定條件,因此為所有記錄執行操作。
total+=$(NF-1) : total變量用於累積每個記錄倒數第二個字段$(NF-1)的值。
最後,我們使用END規則顯示最終total價值。
我們的工作:獲取依賴shell的過程。
$ echo $$
51026第一件事:啟動背景過程。
$ sleep 10 & sleep 15 & sleep 20 &
[1] 86751
[2] 86752
[3] 86753使用ps實用程序, awk將尋找稱為PPID第三個字段。
注意:我們使用-v在執行程序開始之前設置PPID var。
$ ps -ef | awk -v ppid= $$ ' $3==ppid '
501 86751 51026 0 7:57PM ttys001 0:00.00 sleep 10
501 86752 51026 0 7:57PM ttys001 0:00.00 sleep 15
501 86753 51026 0 7:57PM ttys001 0:00.00 sleep 20
0 86754 51026 0 7:57PM ttys001 0:00.00 ps -ef
501 86755 51026 0 7:57PM ttys001 0:00.00 awk $3 ==51026我們只需要睡覺:
$ ps -ef | awk -v ppid= $$ ' $3 == ppid && /slee[p]/
{print $2" -> "$5} '
86751 - > 7:57PM
86752 - > 7:57PM
86753 - > 7:57PM解決方案需要一個新的條件來添加:在我們當前的記錄/slee[p]/中找到睡眠方式。
觸發的動作將是打印第二個字段$2帶有PID的支架和第五$5 ,即時間戳記。
擁有此文件:
$ cat ips.dat
IP BYTES
81.220.49.127 328
81.220.49.127 328
81.220.49.127 329
81.220.49.127 367
81.220.49.127 5302
81.226.10.238 328
81.227.128.93 84700我們的任務是計算每個IP處理多少個字節。
$ awk ' NR>1{ips[$1]+=$2}
END{for (ip in ips){print ip, ips[ip]}} ' ips.dat
81.220.49.127 6654
81.227.128.93 84700
81.226.10.238 328這裡有很多東西要解釋。
NR>1{ips[$1]+=$2} :僅噹噹前記錄號大於一個NR>1操作ips[$1]+=$2才執行。這是避免標題的必要條件。
ips是由IP值( $1字段)索引的數組,對於我們將在第二個字段的值中累積的每個密鑰。
請注意一個重要的事實,如果數組中不存在密鑰, awk將為結構添加一個新元素,否則將更新該密鑰指向的先前值(如我們的示例中)。
END規則僅用於通過索引和值迭代數組。
可以完全以不同的方式重寫此代碼,以避免使用數組,並保留利用排序的IPS文件的訂單:
awk ' NR==1{next}
lip && lip != $1{print lip,sum;sum=0}
{sum+=$2;lip=$1}
END{print lip,sum} ' ips.dat
81.220.49.127 6654
81.226.10.238 328
81.227.128.93 84700 NR==1{next} :繞過標題。
lip && lip != $1{print lip,sum;sum=0} :在這裡我們使用一個名為lip ( last-ip )的var。 lip && lip != $1當lip不為空,並且值不等於第一個字段(保存當前IP)時,觸發的操作將是打印lip並將上一個IP的字節總數sum 。然後,我們將其初始化為sum=0 。
訣竅很明顯,每當IP( $1 )更改時,我們都會顯示上一個統計數據。
{sum+=$2;lip=$1} :要更新字節計數器sum+=$2 ,然後將當前IP分配給lip : lip=$1 。這是我們記錄處理的最後一步。
END塊用於打印待處理值。
該代碼保留了該訂單,但我認為,這是以顯著提高複雜性為代價的。
我們的任務是兩個提取界線和OUTPUT和END之間的界限。
$ cat pat.dat
test -3
test -2
test -1
OUTPUT
top 2
bottom 1
left 0
right 0
page 66
END
test 1
test 2
test 3這是一個經典的示例,用於說明模式匹配如何在awk及其聯想動作中起作用,而我專門介紹了完整的[post]。
$ awk ' /END/{flag=0}flag;/OUTPUT/{flag=1} ' pat.dat
top 2
bottom 1
left 0
right 0
page 66它基於flag變量值,當找到啟動模式OUTPUT並在達到END標籤時,它將是正確的( 1 ) 0
為了避免額外的步驟,如果我們遵循邏輯序列,則操作順序非常重要:
$ awk ' /OUTPUT/{flag=1}flag;/END/{flag=0} ' pat.dat
OUTPUT
top 2
bottom 1
left 0
right 0
page 66
END圖案標籤通過輸出顯示。
原因是:在發現OUTPUT模式後,標誌被激活,因為下一個動作取決於此標誌的記錄。
我們可以避免將標誌激活作為流量的最後一步。
讓我們假設此文件:
$ cat space.dat
10.80 kb
60.08 kb
35.40 kb
2.20 MB
1.10 MB
40.80 kb
3.15 MB
20.50 kb我們的工作將是計算我們的記錄中的總重量:
$ awk ' {total+= $1 / ($2=="kb" ? 1024: 1)}
END{print total} ' space.dat
6.61365要了解它的工作原理,必須清楚一個概念,即[三元]操作員(舊帖子的主題)。
total將使用第二美元的$1來累積第一個字段$2 1的分區,該分數將保留由三元運營商給出的值: 1024當$2等於kb時,如果不需要轉換,則將持有1 。
最後,我們在END塊中打印total價值。
原始來源:
$ cat group.dat
string1
string2
string3
string4
string5
string6
string8我們的任務是在這樣的三列的塊中進行分組記錄:
string1 string2 string3
string4 string5 string6
string8看起來似乎很複雜,但是如果我們了解如何使用輸出字段分離器OFS則變得更加簡單:
$ awk ' ORS = NR%3 ? FS : RS; END{print "n"} ' group.dat
string1 string2 string3
string4 string5 string6
string8如果我們將ORS設置為空白字符,則FS默認值,所有輸出將成為一行:
$ awk ' ORS=FS; END{print "n"} ' group.dat
string1 string2 string3 string4 string5 string6 string7 ORS = NR%3 ? FS : RS :最後,我們使用三元運算符(在此之前進行了解釋)來評估當前場編號NR的[Modulo] NR%3的結果,乘以三。
如果其餘部分為真, ORS變為FS ,則為空白,否則將分配RS默認值, unix lane Break n 。
在生物信息學中,[FastA]是一種基於文本的文件格式。
有以下示例:
$ cat fasta.dat
> header1
CGCTCTCTCCATCTCTCTACCCTCTCCCTCTCTCTCGGATAGCTAGCTCTTCTTCCTCCT
TCCTCCGTTTGGATCAGACGAGAGGGTATGTAGTGGTGCACCACGAGTTGGTGAAGC
> header2
GGT
> header3
TTATGAT我們需要每個序列的總長度和最終簡歷。
應該像這樣:
> header1
117
> header2
3
> header3
7
3 sequences, total length 127 awk是此報告工作的理想工具,對於此示例,我們將使用:
awk ' /^>/ { if (seqlen) {
print seqlen
}
print
seqtotal+=seqlen
seqlen=0
seq+=1
next
}
{
seqlen += length($0)
}
END{print seqlen
print seq" sequences, total length " seqtotal+seqlen
} ' fasta.dat
第一個動作與標題檢測/^>/相關,這是因為所有標頭都帶有> fargun。
當seqlen不為空值時,它的值(以前的序列長度)將打印到附加到新標頭的stdout上。 seqtotal已更新並初始化為seqlen ,以服務下一個序列。最後,我們將與next打破進一步的記錄處理。
第二個操作{seqlen += length($0)}用於更新seqlen ,總結總記錄長度。
END規則目的是顯示未打印的序列和總數。
這裡的技巧是當我們找到新的標頭時打印以前的序列長度。
當我們處理第一個記錄時, seqlen沒有值,因此我們跳過可視化。
來源:
$ cat report.dat
snaps1: Counter: 4966
Opens: Counter: 357283
Instance: s.1.aps.userDatabase.mount275668.attributes
snaps1: Counter: 0
Opens: Counter: 357283
Instance: s.1.aps.userDatabase.test.attributes
snaps1: Counter: 5660
Opens: Counter: 37283
Instance: s.1.aps.userDatabase.mount275000.attributes我們的職責:創建一個報告以可視化snaps和instance ,但僅當快照第一個計數標籤大於零時。
預期輸出:
snaps1: Counter: 4966
Instance: s.1.aps.userDatabase.mount275668.attributes
snaps1: Counter: 5660
Instance: s.1.aps.userDatabase.mount275000.attributes我們正在圍繞圖案和標誌再次玩:
awk ' {$1=$1}
/snaps1/ && $NF>0{print;f=1}
f && /Instance/ {print;f=0} ' report.dat對於每個記錄,執行了第一個動作,它使用當前OFS 3的當前值迫使awk重建整個記錄。
這個技巧使我們能夠將多個空間分離器轉換為單個字符,即輸出字段分離器的默認值。
讓我們看看:
$ awk ' 1 ' text.dat
one two
three four$ awk ' $1=$1 ' text.dat
one two
three four當找到模式並且最後一個字段大於零/snaps1/ && $NF>0 ,將觸發第二個操作。
awk打印記錄並將真實值分配給標誌print;f=1 。
最後一步:當f && /Instance/行中的標誌為真和實例模式時,顯示行並停用標誌: print;f=0 。
讓我們假設兩個檔案:
$ cat join1.dat
3.5 22
5. 23
4.2 42
4.5 44$ cat join2.dat
3.5
3.7
5.
6.5當第一個字段在第二個字段join2.dat中時,我們需要第一個join1.dat的記錄。
輸出應為:
3.5 22
5. 23當然,我們可以使用UNIX加入實用程序,但是我們需要對第一個文件進行排序:
$ join <( sort join1.dat ) join2.dat
3.5 22
5. 23不需要awk :
$ awk ' NR == FNR{a[$1];next}
$1 in a ' join2.dat join1.dat讓我們研究過濾器和動作:
NR == FNR :等於記錄文件號的記錄號表示我們正在處理第一個解析到awk : join2.dat文件。
配對操作a[$1];next是為第一個字段索引的數組添加新的空隙值。 next語句將打破記錄處理,並將流程傳遞到下一個。
對於第二個操作NR != FNR被隱式應用,僅影響join1.dat ,第二個條件為$1 in a當join1.dat的第一個字段是陣列鍵時,第二個條件將是正確的。
這些都是對經典的:
$ cat /etc/group
dba:x:001:
netadmin:x:002:$ cat /etc/passwd
jd001:x:1032:001:Javier Diaz:/home/jd001:/bin/rbash
ag002:x:8050:002:Alejandro Gonzalez:/home/ag002:/bin/rbash
jp003:x:1000:001:Jose Perez:/home/jp003:/bin/bash
ms004:x:8051:002:Maria Saenz:/home/ms004:/bin/rbash
rc005:x:6550:002:Rosa Camacho:/home/rc005:/bin/rbash我們的目標是這樣的報告:
d001:dba
ag002:netadmin
jp003:dba
ms004:netadmin
rc005:netadmin我們需要在上一個示例中研究的多個文件流:
$ awk -F : ' NR == FNR{g[$3]=$1;next}
$4 in g{print $1""FS""g[$4]} ' /etc/group /etc/passwd要處理/etc/group我們重複NR == FNR比較,然後存儲由ID $3索引的組$1的名稱: g[$3]=$1 。最後,我們將與next打破進一步的記錄處理。
第二個條件將僅針對/etc/passwd記錄,當第四個字段$4 (組ID )中存在於$4 in g時,我們將打印登錄名,並由組ID g[$4] print $1""FS""g[$4] 。
用戶實用程序輸出示例:
$ users
negan rick bart klashxx klashxx ironman ironman ironman我們將計算每個用戶的登錄。
$ users | awk ' {a[$1]++}
END{for (i in a){print i,a[i]}} ' RS= ' + '
rick 1
bart 1
ironman 3
negan 1
klashxx 2該動作均為所有記錄執行。
a[$1]++ :這是計數器,對於每個用戶$1它會增加尖銳的值(非初始化的VAR具有數值值零)。
END阻止迭代數組按鍵和存儲的值介紹結果。
一個典型的輸出:
$ uptime
11:08:51 up 121 days, 13:09, 10 users, load average: 9.12, 14.85, 20.84我們如何獲得總負載平均值的意思?
$ uptime | awk ' {printf "Load average mean: %0.2fn",
($(NF-2)+$(NF-1)+$(NF))/3 } ' FS= ' (:|,) + '
Load average mean: 14.94這是一種新技術。
我們使用[Regex]作為場分離器(:|,) + ,因此FS可以是結腸和逗號,然後是零或更多空白空間。
我們只需要最後三個字段來執行所需的算術,然後使用附加在適當掩碼上的printf即可。
如果您還在這裡,謝謝!
從我的角度來看, awk是一種被低估的語言,需要很多愛。
如果您渴望更多,請在評論部分Bellow中告訴我,我將考慮第二部分來完成我的任務……使您致死。
愉快的編碼!
[UNIX Shell引用指南] [引用指南]。 ↩
[管道上的Wikipedia] [管道]。 ↩
有時候,使用FS和OFS的當前值強迫awk強迫AWK重建整個記錄。
為此,我們使用看似無害的作業: $1 = $1 1↩2
快速答案,這只是避免使用打印語句的快捷方式。
awk條件得到匹配時,默認操作是打印輸入行。
$ echo "test" |awk '1'
等同於:
echo "test"|awk '1==1'
echo "test"|awk '{if (1==1){print}}'
那是因為1將永遠[true]。 ↩