该文本仅指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]。 ↩