awk最全详解及实例操作

awk简介
awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

awk 是一种很棒的语言,它适合文本处理和报表生成,其语法较为常见,借鉴了某些语言的一些精华,如 C 语言等。在 linux 系统日常处理工作中,发挥很重要的作用,掌握了 awk将会使你的工作变的高大上。 awk 是三剑客的老大,利剑出鞘,必会不同凡响。

使用方法
1
awk '{pattern + action}' {filenames}
尽管操作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。 pattern就是要表示的正则表达式,用斜杠括起来。

awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。

通常,awk是以文件的一行为处理单位的。awk每接收文件的一行,然后执行相应的命令,来处理文本。

awk 的原理
通过一个简短的命令,我们来了解其工作原理。 

[root@Gin scripts]# awk '{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
.....................................................
 
[root@Gin scripts]# echo hhh|awk '{print "hello,world"}'
hello,world
 
[root@Gin scripts]# awk '{print "hiya"}' /etc/passwd
hiya
hiya
hiya
hiya
...............................................
你将会见到/etc/passwd 文件的内容出现在眼前。现在,解释 awk 做了些什么。调用 awk时,我们指定/etc/passwd 作为输入文件。执行 awk 时,它依次对/etc/passwd 中的每一行执行 print 命令。

所有输出都发送到 stdout,所得到的结果与执行 cat /etc/passwd 完全相同。
现在,解释{ print }代码块。在 awk 中,花括号用于将几块代码组合到一起,这一点类似于 C 语言。在代码块中只有一条 print 命令。在 awk 中,如果只出现 print 命令,那么将打印当前行的全部内容。
再次说明, awk 对输入文件中的每一行都执行这个脚本。

$ awk -F":" '{ print $1 }' /etc/passwd
$ awk -F":" '{ print $1 $3 }' /etc/passwd
$ awk -F":" '{ print $1 " " $3 }' /etc/passwd
$ awk -F":" '{ print "username: " $1 "\t\tuid:" $3" }' /etc/passwd
-F参数:指定分隔符,可指定一个或多个

awk时间字段截取
date=`date +%Y%m%d`  
month=`echo $date | awk '{print substr($0, 5, 2)}'`  

print 后面做字符串的拼接

下面通过几实例来了解下awk的工作原理:
实例一:只查看test.txt文件(100行)内第20到第30行的内容(企业面试)
 
[root@Gin scripts]# awk '{if(NR>=20 && NR<=30) print $1}' test.txt   
20
21
22
23
24
25
26
27
28
29
30

实例二:已知test.txt文件内容为:
[root@Gin scripts]# cat test.txt
I am Poe,my qq is 33794712
请从该文件中过滤出'Poe'字符串与33794712,最后输出的结果为:Poe 33794712

[root@Gin scripts]# awk -F '[ ,]+' '{print $3" "$7}' test.txt
Poe 33794712
BEGIN 和 END 模块
通常,对于每个输入行, awk 都会执行每个脚本代码块一次。然而,在许多编程情况中,可能需要在 awk 开始处理输入文件中的文本之前执行初始化代码。对于这种情况, awk 允许您定义一个 BEGIN 块。

因为 awk 在开始处理输入文件之前会执行 BEGIN 块,因此它是初始化 FS(字段分隔符)变量、打印页眉或初始化其它在程序中以后会引用的全局变量的极佳位置。
awk 还提供了另一个特殊块,叫作 END 块。 awk 在处理了输入文件中的所有行之后执行这个块。通常, END 块用于执行最终计算或打印应该出现在输出流结尾的摘要信息。

实例一:统计/etc/passwd的账户人数
[root@Gin scripts]# awk '{count++;print $0;} END{print "user count is ",count}' passwd
root:x:0:0:root:/root:/bin/bash
..............................................
user count is  27
count是自定义变量。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开。这里没有初始化count,虽然默认是0,但是妥当的做法还是初始化为0:

[root@Gin scripts]# awk 'BEGIN {count=0;print "[start] user count is ",count} {count=count+1;print $0} END{print "[end] user count is ",count}' passwd
[start] user count is  0
root:x:0:0:root:/root:/bin/bash
...................................................................
[end] user count is  27
实例二:统计某个文件夹下的文件占用的字节数

[root@Gin scripts]# ll |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ",size}'
[end]size is  1489
如果以M为单位显示:

1
2
[root@Gin scripts]# ll |awk 'BEGIN{size=0;} {size=size+$5;} END{print "[end]size is ",size/1024/1024,"M"}'   
[end]size is  0.00142002 M
 

awk运算符


awk 赋值运算符:a+5;等价于: a=a+5;其他同类
[root@Gin scripts]# awk 'BEGIN{a=5;a+=5;print a}'
10
awk逻辑运算符:

[root@Gin scripts]# awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'
0 1
判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符:

[root@Gin scripts]# awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'
ok

[root@Gin scripts]# echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'
ok
关系运算符:
如: > < 可以作为字符串比较,也可以用作数值比较,关键看操作数如果是字符串就会转换为字符串比较。两个都为数字 才转为数值比较。字符串比较:按照ascii码顺序比较。

[root@Gin scripts]# awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出
[root@Gin scripts]# awk 'BEGIN{a=11;if(a>=9){print "ok"}}' 
ok
[root@Gin scripts]# awk 'BEGIN{a;if(a>=b){print "ok"}}'
ok
awk 算术运算符:
说明,所有用作算术运算符进行操作,操作数自动转为数值,所有非数值都变为0。

[root@Gin scripts]# awk 'BEGIN{a="b";print a++,++a}'
0 2
[root@Gin scripts]# awk 'BEGIN{a="20b4";print a++,++a}'
20 22
这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?:

[root@Gin scripts]# awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'
ok
[root@Gin scripts]# awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'
err
 常用 awk 内置变量 


 注:内置变量很多,参阅相关资料

字段分隔符 FS
FS="\t" 一个或多个 Tab 分隔

[root@Gin scripts]# cat tab.txt
ww   CC        IDD
[root@Gin scripts]# awk 'BEGIN{FS="\t+"}{print $1,$2,$3}' tab.txt
ww   CC        IDD
FS="[[:space:]+]" 一个或多个空白空格,默认的 

[root@Gin scripts]# cat space.txt
we are    studing awk now!
[root@Gin scripts]# awk -F [[:space:]+] '{print $1,$2,$3,$4,$5}' space.txt
we are  
[root@Gin scripts]# awk -F [[:space:]+] '{print $1,$2}' space.txt
we are
FS="[" ":]+" 以一个或多个空格或:分隔 

[root@Gin scripts]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
[root@Gin scripts]# awk -F [" ":]+ '{print $1,$2,$3}' hello.txt
root x 0
字段数量 NF 


[root@Gin scripts]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin:888
[root@Gin scripts]# awk -F ":" 'NF==8{print $0}' hello.txt
bin:x:1:1:bin:/bin:/sbin/nologin:888
记录数量 NR

1
2
[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print $4}'  ## NR==2也就是取第2行
192.168.17.129
RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@Gin scripts]# cat recode.txt
Jimmy the Weasel
100 Pleasant Drive
San Francisco,CA 123456
 
Big Tony
200 Incognito Ave.
Suburbia,WA 64890
[root@Gin scripts]# cat awk.txt
#!/bin/awk
BEGIN {
        FS="\n"
        RS=""
}
{
        print $1","$2","$3
}
[root@Gin scripts]# awk -f awk.txt recode.txt
Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456
Big Tony,200 Incognito Ave.,Suburbia,WA 64890
OFS 输出字段分隔符 

1
2
3
4
5
6
7
8
9
[root@Gin scripts]# cat hello.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin:888
[root@Gin scripts]# awk 'BEGIN{FS=":"}{print $1","$2","$3}' hello.txt
root,x,0
bin,x,1
[root@Gin scripts]# awk 'BEGIN{FS=":";OFS="#"}{print $1,$2,$3}' hello.txt
root#x#0
bin#x#1
ORS 输出记录分隔符 

[root@Gin scripts]# cat recode.txt
Jimmy the Weasel
100 Pleasant Drive
San Francisco,CA 123456
 
Big Tony
200 Incognito Ave.
Suburbia,WA 64890
[root@Gin scripts]# cat awk.txt
#!/bin/awk
BEGIN {
        FS="\n"
        RS=""
        ORS="\n\n"
}
{
        print $1","$2","$3
}
[root@Gin scripts]# awk -f awk.txt recode.txt
Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456
 
Big Tony,200 Incognito Ave.,Suburbia,WA 64890
 awk 正则 


 正则应用
规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

[root@Gin scripts]# awk '/root/{print $0}' passwd ##匹配所有包含root的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
 
[root@Gin scripts]# awk -F: '$5~/root/{print $0}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行
root:x:0:0:root:/root:/bin/bash
 
[root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print $4}'
192.168.17.129
布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。

[root@Gin scripts]# awk -F: '$1=="root"{print $0}' passwd
root:x:0:0:root:/root:/bin/bash
[root@Gin scripts]# awk -F: '($1=="root")&&($5=="root") {print $0}' passwd
root:x:0:0:root:/root:/bin/bash
 awk 的 if、循环和数组 
条件语句
awk 提供了非常好的类似于 C 语言的 if 语句。

{
        if ($1=="foo"){
                if($2=="foo"){
                        print "uno"
                }else{
                        print "one"
                }
        }elseif($1=="bar"){
                print "two"
        }else{
                print "three"
        }
}
使用 if 语句还可以将代码: 

1
! /matchme/ { print $1 $3 $4 }
转换成:

{
if ( $0 !~ /matchme/ ) {
print $1 $3 $4
}
}
循环结构
我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。

它类似于其它语言中的"repeat...until"循环。以下是一个示例:
do...while 示例

{
    count=1do {
        print "I get printed at least once no matter what"
    } while ( count !=1 )
}
与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。

for 循环
awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

for ( initial assignment; comparison; increment ) {
    code block
}
以下是一个简短示例: 

for ( x=1;x<=4;x++ ) {
    print "iteration", x
}
此段代码将打印: 

iteration1
iteration2
iteration3
iteration4
break 和 continue
此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。使用这些语句可以更好地控制 awk 的循环结构。以下是迫切需要 break 语句的代码片断:

while 死循环
while (1) {
print "forever and ever..."
}
while 死循环 1 永远代表是真,这个 while 循环将永远运行下去。
以下是一个只执行十次的循环: 

#break 语句示例
x=1
while(1) {
print "iteration", x
if ( x==10 ) {
break
}
x++
}
这里, break 语句用于“逃出”最深层的循环。 "break"使循环立即终止,并继续执行循环代码块后面的语句。
continue 语句补充了 break,其作用如下:

x=1while (1) {
        if ( x==4 ) {
        x++
        continue
    }
    print "iteration", x
    if ( x>20 ) {
        break
    }
    x++
}
这段代码打印"iteration1"到"iteration21", "iteration4"除外。如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。如同 break 一样,

continue 语句适合各种 awk 迭代循环。在 for 循环主体中使用时, continue 将使循环控制变量自动增加。以下是一个等价循环:

for ( x=1;x<=21;x++ ) {
    if ( x==4 ) {
        continue
    }
    print "iteration", x
}
在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。 

数组 
AWK 中的数组都是关联数组,数字索引也会转变为字符串索引 

{
    cities[1]=”beijing”
    cities[2]=”shanghai”
    cities[“three”]=”guangzhou”
    for( c in cities) {
        print cities[c]
    }
    print cities[1]
    print cities[“1”]
    print cities[“three”]
}
for…in 输出,因为数组是关联数组,默认是无序的。所以通过 for…in 得到是无序的数组。如果需要得到有序数组,需要通过下标获得。

数组的典型应用
用 awk 中查看服务器连接状态并汇总 

netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}'
ESTABLISHED 1
LISTEN 20
统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总


awk '{a[$7]+=$10;++b[$7];total+=$10}END{for(x in a)print b[x],x,a[x]|"sort -rn -k1";print
"total size is :"total}' /app/log/access_log
total size is :172230
21 /icons/poweredby.png 83076
14 / 70546
8 /icons/apache_pb.gif 18608
a[$7]+=$10 表示以第 7 列为下标的数组( $10 列为$7 列的大小),把他们大小累加得到
$7 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一
条 for 语句足矣
常用字符串函数


字符串函数的应用 
替换 

awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}' this is a test!test!
在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未
给 info 值,默认是$0
查找 


awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'
ok #未找到,返回 0
匹配查找 


awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'
ok #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到
截取 

awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'
s is a tes #从第 4 个 字符开始,截取 10 个长度字符串
分割 


awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4
4 test 1 this 2 is 3 a
#分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。 并不是从数组下标
1…n 开始


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息
awk处理过程: 依次对每一行进行处理,然后输出
awk命令形式:
awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
 [-F|-f|-v]   大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
'  '          引用代码块
BEGIN   初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
//           匹配代码块,可以是字符串或正则表达式
{}           命令代码块,包含一条或多条命令
;          多条命令使用分号分隔
END      结尾代码块,在对每一行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息
 
特殊要点:
$0           表示整个当前行
$1           每行第一个字段
NF          字段数量变量
NR          每行的记录号,多文件记录递增
FNR        与NR类似,不过多文件记录不递增,每个文件都从1开始
\t            制表符
\n           换行符
FS          BEGIN时定义分隔符
RS       输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
~            匹配,与==相比不是精确比较
!~           不匹配,不精确比较
==         等于,必须全部相等,精确比较
!=           不等于,精确比较
&&      逻辑与
||             逻辑或
+            匹配时表示1个或1个以上
/[0-9][0-9]+/   两个或两个以上数字
/[0-9][0-9]*/    一个或一个以上数字
FILENAME 文件名
OFS      输出字段分隔符, 默认也是空格,可以改为制表符等
ORS        输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
-F'[:#/]'   定义三个分隔符
 
print & $0
print 是awk打印指定内容的主要命令
awk '{print}'  /etc/passwd   ==   awk '{print $0}'  /etc/passwd  
awk '{print " "}' /etc/passwd                                           //不输出passwd的内容,而是输出相同个数的空行,进一步解释了awk是一行一行处理文本
awk '{print "a"}'   /etc/passwd                                        //输出相同个数的a行,一行只有一个a字母
awk -F":" '{print $1}'  /etc/passwd 
awk -F: '{print $1; print $2}'   /etc/passwd                   //将每一行的前二个字段,分行输出,进一步理解一行一行处理文本
awk  -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd        //输出字段1,3,6,以制表符作为分隔符
 
-f指定脚本文件
awk -f script.awk  file
BEGIN{
FS=":"
}
{print $1}               //效果与awk -F":" '{print $1}'相同,只是分隔符使用FS在代码自身中指定
 
awk 'BEGIN{X=0} /^$/{ X+=1 } END{print "I find",X,"blank lines."}' test 
I find 4 blank lines.
 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is",sum}'                    //计算文件大小
total size is 17487
 
-F指定分隔符
$1 指指定分隔符后,第一个字段,$3第三个字段, \t是制表符
一个或多个连续的空格或制表符看做一个定界符,即多个空格看做一个空格
awk -F":" '{print $1}'  /etc/passwd
awk -F":" '{print $1 $3}'  /etc/passwd                       //$1与$3相连输出,不分隔
awk -F":" '{print $1,$3}'  /etc/passwd                       //多了一个逗号,$1与$3使用空格分隔
awk -F":" '{print $1 " " $3}'  /etc/passwd                  //$1与$3之间手动添加空格分隔
awk -F":" '{print "Username:" $1 "\t\t Uid:" $3 }' /etc/passwd       //自定义输出  
awk -F: '{print NF}' /etc/passwd                                //显示每行有多少字段
awk -F: '{print $NF}' /etc/passwd                              //将每行第NF个字段的值打印出来
 awk -F: 'NF==4 {print }' /etc/passwd                       //显示只有4个字段的行
awk -F: 'NF>2{print $0}' /etc/passwd                       //显示每行字段数量大于2的行
awk '{print NR,$0}' /etc/passwd                                 //输出每行的行号
awk -F: '{print NR,NF,$NF,"\t",$0}' /etc/passwd      //依次打印行号,字段数,最后字段值,制表符,每行内容
awk -F: 'NR==5{print}'  /etc/passwd                         //显示第5行
awk -F: 'NR==5 || NR==6{print}'  /etc/passwd       //显示第5行和第6行
route -n|awk 'NR!=1{print}'                                       //不显示第一行
 
//匹配代码块
//纯字符匹配   !//纯字符不匹配   ~//字段值匹配    !~//字段值不匹配   ~/a1|a2/字段值匹配a1或a2   
awk '/mysql/' /etc/passwd
awk '/mysql/{print }' /etc/passwd
awk '/mysql/{print $0}' /etc/passwd                   //三条指令结果一样
awk '!/mysql/{print $0}' /etc/passwd                  //输出不匹配mysql的行
awk '/mysql|mail/{print}' /etc/passwd
awk '!/mysql|mail/{print}' /etc/passwd
awk -F: '/mail/,/mysql/{print}' /etc/passwd         //区间匹配
awk '/[2][7][7]*/{print $0}' /etc/passwd               //匹配包含27为数字开头的行,如27,277,2777...
awk -F: '$1~/mail/{print $1}' /etc/passwd           //$1匹配指定内容才显示
awk -F: '{if($1~/mail/) print $1}' /etc/passwd     //与上面相同
awk -F: '$1!~/mail/{print $1}' /etc/passwd          //不匹配
awk -F: '$1!~/mail|mysql/{print $1}' /etc/passwd        
 
IF语句
必须用在{}中,且比较内容用()扩起来
awk -F: '{if($1~/mail/) print $1}' /etc/passwd                                       //简写
awk -F: '{if($1~/mail/) {print $1}}'  /etc/passwd                                   //全写
awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd            //if...else...
 
 
条件表达式
==   !=   >   >=  
awk -F":" '$1=="mysql"{print $3}' /etc/passwd  
awk -F":" '{if($1=="mysql") print $3}' /etc/passwd          //与上面相同 
awk -F":" '$1!="mysql"{print $3}' /etc/passwd                 //不等于
awk -F":" '$3>1000{print $3}' /etc/passwd                      //大于
awk -F":" '$3>=100{print $3}' /etc/passwd                     //大于等于
awk -F":" '$3<1{print $3}' /etc/passwd                            //小于
awk -F":" '$3<=1{print $3}' /etc/passwd                         //小于等于
 
逻辑运算符
&& || 
awk -F: '$1~/mail/ && $3>8 {print }' /etc/passwd         //逻辑与,$1匹配mail,并且$3>8
awk -F: '{if($1~/mail/ && $3>8) print }' /etc/passwd
awk -F: '$1~/mail/ || $3>1000 {print }' /etc/passwd       //逻辑或
awk -F: '{if($1~/mail/ || $3>1000) print }' /etc/passwd 
 
数值运算
awk -F: '$3 > 100' /etc/passwd    
awk -F: '$3 > 100 || $3 < 5' /etc/passwd  
awk -F: '$3+$4 > 200' /etc/passwd
awk -F: '/mysql|mail/{print $3+10}' /etc/passwd                    //第三个字段加10打印 
awk -F: '/mysql/{print $3-$4}' /etc/passwd                             //减法
awk -F: '/mysql/{print $3*$4}' /etc/passwd                             //求乘积
awk '/MemFree/{print $2/1024}' /proc/meminfo                  //除法
awk '/MemFree/{print int($2/1024)}' /proc/meminfo           //取整
 
输出分隔符OFS
awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt
awk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt        
//输出字段6匹配WAIT的行,其中输出每行行号,字段4,5,6,并使用制表符分割字段
 
输出处理结果到文件
①在命令代码块中直接输出    route -n|awk 'NR!=1{print > "./fs"}'   
②使用重定向进行输出           route -n|awk 'NR!=1{print}'  > ./fs
 
格式化输出
netstat -anp|awk '{printf "%-8s %-8s %-10s\n",$1,$2,$3}' 
printf表示格式输出
%格式化输出分隔符
-8长度为8个字符
s表示字符串类型
打印每行前三个字段,指定第一个字段输出字符串类型(长度为8),第二个字段输出字符串类型(长度为8),
第三个字段输出字符串类型(长度为10)
netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-10s %-10s %-10s \n",$1,$2,$3}'
netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-3s %-10s %-10s %-10s \n",NR,$1,$2,$3}'
 
IF语句
awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd
small
small
small
large
small
small
awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd 
                                                                                                                  //ID大于100,A加1,否则B加1
awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示
awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd   
awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd
另一种形式
awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd 
awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd
 
while语句
awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd 
7 root 1
7 x 2
7 0 3
7 0 4
7 root 5
7 /root 6
 
数组
netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}'
netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}'
9523                               1     
9929                               1     
LISTEN                            6     
7903                               1     
3038/cupsd                   1     
7913                               1     
10837                             1     
9833                               1     
 
应用1
awk -F: '{print NF}' helloworld.sh                                                       //输出文件每行有多少字段
awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh                                 //输出前5个字段
awk -F: '{print $1,$2,$3,$4,$5}' OFS='\t' helloworld.sh                 //输出前5个字段并使用制表符分隔输出
awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号
 
应用2
awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段
awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段
 
应用3
awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数
awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段
 
应用4
计算/home目录下,普通文件的大小,使用KB作为单位
ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}'
ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思
 
应用5
统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少
netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'
 
应用6
统计/home目录下不同用户的普通文件的总数是多少?
ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'   
mysql        199 
root           374 
统计/home目录下不同用户的普通文件的大小总size是多少?
ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'
 
应用7
输出成绩表
awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\n";printf "------------------------------------------------------------\n"}{math+=$3; eng+=$4; com+=$5;printf "%-8s %-7s %-7s %-7s %-9s %-10s %-7s \n",NR,$1,$2,$3,$4,$5,$3+$4+$5} END{printf "------------------------------------------------------------\n";printf "%-24s %-7s %-9s %-20s \n","Total:",math,eng,com;printf "%-24s %-7s %-9s %-20s \n","Avg:",math/NR,eng/NR,com/NR}' test0


版权声明:本文为qq_32330469原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。